tags:

views:

118

answers:

4

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?

Thanks in advance!

A: 

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.

Joe Kington
Touching `__dict__` directly is basically always wrong.
Aaron Gallagher
@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
@Joe, no, reading it is basically always wrong as well. It bypasses the descriptor protocol, not to mention it relies on an implementation detail.
Aaron Gallagher
@Aaron - True, I guess I didn't think far enough into it.
Joe Kington
It 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
+4  A: 

@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.

delnan
"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
@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
Yes, the builtins don't do this. Sorry if it read like that.
delnan
objects with `__slots__` don't have `__dict__` either
gnibbler
The 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.
THC4k
+2  A: 

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
Aaron Gallagher
A: 

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

gnibbler