Reputation: 7052
I have the following code.
class person(object):
def __init__(self, keys):
for item in keys:
setattr(self, item, None)
def __str__(self):
return str(self.__dict__)
def __eq__(self, other) :
return self.__dict__ == other.__dict__
Now I want to take this code and only do __eq__
on a specific set of attrs ("keys"). So I changed it to do this:
class person(object):
def __init__(self, keys):
self.valid_keys = keys
for item in keys:
setattr(self, item, None)
def __str__(self):
return dict([(i, getattr(self, i)) for i in self.valid_keys ])
def __eq__(self, other) :
assert isinstance(other, person)
self_vals = [ getattr(self, i) for i in self.valid_keys ]
other_vals = [ getattr(other, i) for i in self.valid_keys ]
return self_vals == other_vals
I have read the following two awesome posts (here and here) and my fundamental question is:
Is this the right approach or is there a better way to do this in python?
Obviously TMTOWTDI - but I'd like to keep and follow a standard pythonic approach. Thanks!!
Updates
I was asked why do I not fix the attrs in my class. This is a great question and here's why. The purpose of this is to take several dis-jointed employee records and build a complete picture of an employee. For example I get my data from ldap, lotus notes, unix passwd files, bugzilla data, etc. Each of those has uniq attrs and so I generalized them into a person. This gives me a quick consistent way to compare old records to new records. HTH. Thanks
** Updates Pt.2 **
Here is what I ended up with:
class personObj(object):
def __init__(self, keys):
self.__dict__ = dict.fromkeys(keys)
self.valid_keys = keys
def __str__(self):
return str([(i, getattr(self, i)) for i in self.valid_keys ])
def __eq__(self, other):
return isinstance(other, personObj) and all(getattr(self, i) == getattr(other, i) for i in self.valid_keys)
Thanks to both gents for reviewing!
Upvotes: 0
Views: 174
Reputation: 882691
There are minor enhancements (bug fixes) I'd definitely do.
In particular, getattr
called with two arguments raises an ArgumentError if the attribute's not present, so you could get that exception if you were comparing two instances with different keys. You could just call it with three args instead (the third one is returned as the default value when the attribute is not present) -- just don't use None
as the third arg in this case since it's what you normally have as the value (use a sentinel value as the third arg).
__str__
is not allowed to return a dict: it must return a string.
__eq__
between non-comparable objects should not raise -- it should return False.
Bugs apart, you can get the object's state very compactly with self.__dict__
, or more elegantly with vars(self)
(you can't reassign the whole dict with the latter syntax, though). This bit of knowledge lets you redo your class entirely, in a higher-level-of-abstraction way -- more compact and expeditious:
class person(object):
def __init__(self, keys):
self.__dict__ = dict.fromkeys(keys)
def __str__(self):
return str(vars(self))
def __eq__(self, other):
return isinstance(other, person) and vars(self) == vars(other)
Upvotes: 2
Reputation: 376012
You can simplify your comparison from:
self_vals = [ getattr(self, i) for i in self.valid_keys ]
other_vals = [ getattr(other, i) for i in self.valid_keys ]
return self_vals == other_vals
to:
return all(getattr(self, i) == getattr(other, i) for i in self.valid_keys)
Upvotes: 1