Is there any way to check if two objects have the same values, other than to iterate through their attributes and manually compare their values?
4 Answers
@Joe Kington's solutions works if there is a __dict__
(some objects, including builtins, don't have one) and __eq__
works for all values of both dicts (a badly written __eq__
mayraise exceptions etc). But it is horribly unpythonic. It doesn't even handle nominal subtypes properly... much less structural subtypes (i.e. types that you can use in place/for duck-typing). Do not do this.
But usually you're better off with a hand-tailored __eq__
method that only compares some attributes that are significant. E.g. Rational should only compare numerator and denominator, nothing more.
-
2"some meaningless comparisions may raise exceptions": nope, this applies only to comparisons involving ordering -- checking if `a` equals `b` (i.e., `a==b`, expressed or implied) **never** causes exceptions (unless you deliberately code a weird class overriding `__eq__` for the sole purpose of causing such exceptions;-). IOW, comparison for equality / inequality is **never** "meaningless". – Alex Martelli Aug 23 '10 at 18:29
-
@Alex Or unless somebody else codes such a class. Badly written classes occur pretty frequently. But, delnan seemed to imply that some builtin types behaved this way, which is indeed incorrect. – Devin Jeanpierre Aug 23 '10 at 18:37
-
-
2The problem is that testing equality can be completely senseless, so it'd be responsible to raise exceptions in that case! I more than once cursed at Python for not raising anything in `func==42` when I actually wanted to write `func()==42`. But we can never do this, even when the test is meaningless, because we want `something in (True, len, object)` to work at the same time. – Jochen Ritzel Aug 23 '10 at 20:12
To expound on delnan's answer:
_NOTFOUND = object()
class Rational(object):
def __eq__(self, other):
for attr in ['numerator', 'denominator']:
v1, v2 = [getattr(obj, attr, _NOTFOUND) for obj in [self, other]]
if v1 is _NOTFOUND or v2 is _NOTFOUND:
return False
elif v1 != v2:
return False
return True

- 9,906
- 3
- 32
- 26
You can compare namedtuple directly.
Otherwise you have to define either your own rich comparisons __eq__
and possibly __ne__
or your own __cmp__
see the datamodel for more info

- 295,403
- 53
- 369
- 502
object1.__dict__ == object2.__dict__
Should be all you need, I think...
Edit: vars(object1) == vars(object2)
is perhaps a bit more pythonic, though @delnan makes a valid point about objects (e.g. int
s) that don't have a __dict__
. I disagree that a custom __eq__
is a better approach for simple cases, though... Sometimes it's not worth the effort to go beyond quick and dirty, if quick and dirty perfectly does what you need, i.m.h.o.

- 275,208
- 71
- 604
- 463
-
3@Aaron, I'd agree that modifying `__dict__` directly is basically always wrong... I'd disagree that reading it directly is basically always wrong. Perhaps `vars` is a bit clearer, though... – Joe Kington Aug 23 '10 at 18:43
-
3no, reading it is basically always wrong as well. It bypasses the descriptor protocol, not to mention it relies on an implementation detail. – habnabit Aug 23 '10 at 18:43
-
1
-
1It also fails in the case of `__slots__`. `__slots__` shows that it's not just about implementation details of Python implementations, it's implementation details of objects within CPython. Accessing `__dict__` directly (or indirectly through `vars()`) is bad. – Devin Jeanpierre Aug 23 '10 at 18:46