|Ned Batchelder : Blog | Code | Text | Site|
» Home : Blog : January 2012
Hanging out in the #python IRC channel today, I learned something new about Python comparisons. It isn't so much a new detail of the language, as a way to make use of a detail, a clever technique that I hadn't seen before.
When defining a class, it's often useful to define an equality comparison so that instances of your class can be considered equal. For example, in an object with three attributes, the typical way to define __eq__ is like this:
When run, it shows what happens:
Here the __eq__ method compares the three attributes directly on the self and other objects, and returns a boolean, a simple direct comparison.
But on IRC, a different technique was proposed:
Now when we run it, something unusual happens:
Our __eq__ is being called twice! The first time, it's called with two Thing objects, and it tries to compare a tuple of (1, 2, 3) to other, which is y, which is a Thing. Tuples don't support comparison to Thing's, so it returns NotImplemented. The == operator handles that case, and relying on the commutative nature of ==, tries swapping the two arguments. That means comparing y to (1, 2, 3), which calls our __eq__ again. Now it compares (1, 2, 3) to (1, 2, 3), which succeeds, producing the final True result.
This is an interesting technique, but I'm not sure I like it. For one thing, the code doesn't read clearly. It's comparing a tuple to an object, which isn't supported. It only makes sense when you keep in mind the argument-swapping dance.
For another, it make operations work that maybe shouldn't:
I don't know that I want these comparisons to succeed. It exposes internals that should be hidden. Of course, why would a caller who didn't know the internals try a comparison like this? But things like this have a way of creeping out to bite you.
I'm glad to have a better understanding of the workings of comparisons, but I'm not sure I'll write them like this.
tagged: python» 8 reactions