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. ints) 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
 
    