Overload operators in Python inherits situation [duplicate] - python

Since Python does not provide left/right versions of its comparison operators, how does it decide which function to call?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
This seems to call both __eq__ functions.
I am looking for the official decision tree.

The a == b expression invokes A.__eq__, since it exists. Its code includes self.value == other. Since int's don't know how to compare themselves to B's, Python tries invoking B.__eq__ to see if it knows how to compare itself to an int.
If you amend your code to show what values are being compared:
class A(object):
def __eq__(self, other):
print("A __eq__ called: %r == %r ?" % (self, other))
return self.value == other
class B(object):
def __eq__(self, other):
print("B __eq__ called: %r == %r ?" % (self, other))
return self.value == other
a = A()
a.value = 3
b = B()
b.value = 4
a == b
it will print:
A __eq__ called: <__main__.A object at 0x013BA070> == <__main__.B object at 0x013BA090> ?
B __eq__ called: <__main__.B object at 0x013BA090> == 3 ?

When Python2.x sees a == b, it tries the following.
If type(b) is a new-style class, and type(b) is a subclass of type(a), and type(b) has overridden __eq__, then the result is b.__eq__(a).
If type(a) has overridden __eq__ (that is, type(a).__eq__ isn't object.__eq__), then the result is a.__eq__(b).
If type(b) has overridden __eq__, then the result is b.__eq__(a).
If none of the above are the case, Python repeats the process looking for __cmp__. If it exists, the objects are equal iff it returns zero.
As a final fallback, Python calls object.__eq__(a, b), which is True iff a and b are the same object.
If any of the special methods return NotImplemented, Python acts as though the method didn't exist.
Note that last step carefully: if neither a nor b overloads ==, then a == b is the same as a is b.
From https://eev.ee/blog/2012/03/24/python-faq-equality/

Python 3 Changes/Updates for this algorithm
How is __eq__ handled in Python and in what order?
a == b
It is generally understood, but not always the case, that a == b invokes a.__eq__(b), or type(a).__eq__(a, b).
Explicitly, the order of evaluation is:
if b's type is a strict subclass (not the same type) of a's type and has an __eq__, call it and return the value if the comparison is implemented,
else, if a has __eq__, call it and return it if the comparison is implemented,
else, see if we didn't call b's __eq__ and it has it, then call and return it if the comparison is implemented,
else, finally, do the comparison for identity, the same comparison as is.
We know if a comparison isn't implemented if the method returns NotImplemented.
(In Python 2, there was a __cmp__ method that was looked for, but it was deprecated and removed in Python 3.)
Let's test the first check's behavior for ourselves by letting B subclass A, which shows that the accepted answer is wrong on this count:
class A:
value = 3
def __eq__(self, other):
print('A __eq__ called')
return self.value == other.value
class B(A):
value = 4
def __eq__(self, other):
print('B __eq__ called')
return self.value == other.value
a, b = A(), B()
a == b
which only prints B __eq__ called before returning False.
Note that I also correct a small error in the question where self.value is compared to other instead of other.value - in this comparison, we get two objects (self and other), usually of the same type since we are doing no type-checking here (but they can be of different types), and we need to know if they are equal. Our measure of whether or not they are equal is to check the value attribute, which must be done on both objects.
How do we know this full algorithm?
The other answers here seem incomplete and out of date, so I'm going to update the information and show you how how you could look this up for yourself.
This is handled at the C level.
We need to look at two different bits of code here - the default __eq__ for objects of class object, and the code that looks up and calls the __eq__ method regardless of whether it uses the default __eq__ or a custom one.
Default __eq__
Looking __eq__ up in the relevant C api docs shows us that __eq__ is handled by tp_richcompare - which in the "object" type definition in cpython/Objects/typeobject.c is defined in object_richcompare for case Py_EQ:.
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue #1393. */
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
So here, if self == other we return True, else we return the NotImplemented object. This is the default behavior for any subclass of object that does not implement its own __eq__ method.
How __eq__ gets called
Then we find the C API docs, the PyObject_RichCompare function, which calls do_richcompare.
Then we see that the tp_richcompare function, created for the "object" C definition is called by do_richcompare, so let's look at that a little more closely.
The first check in this function is for the conditions the objects being compared:
are not the same type, but
the second's type is a subclass of the first's type, and
the second's type has an __eq__ method,
then call the other's method with the arguments swapped, returning the value if implemented. If that method isn't implemented, we continue...
if (!Py_IS_TYPE(v, Py_TYPE(w)) &&
PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
(f = Py_TYPE(w)->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Next we see if we can lookup the __eq__ method from the first type and call it.
As long as the result is not NotImplemented, that is, it is implemented, we return it.
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Else if we didn't try the other type's method and it's there, we then try it, and if the comparison is implemented, we return it.
if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
Finally, we get a fallback in case it isn't implemented for either one's type.
The fallback checks for the identity of the object, that is, whether it is the same object at the same place in memory - this is the same check as for self is other:
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
Conclusion
In a comparison, we respect the subclass implementation of comparison first.
Then we attempt the comparison with the first object's implementation, then with the second's if it wasn't called.
Finally we use a test for identity for comparison for equality.

Related

How does one make Python objects hashable when there is nothing to distinguish them?

Let's say I want to use a set() to store a bunch of objects whose only distinction is that they exist and are not other instances of the same class. Otherwise, they are not distinguishable, e.g., no def __eq__(self, other): return self.qux == other.qux, because that qux is the same (or random) for all of them. How do you define an __eq__ and __hash__ function for that class?
You don't need to implement either __eq__ or __hash__.
User-defined classes have __eq__() and __hash__() methods by
default; with them, all objects compare unequal (except with
themselves) and x.__hash__() returns an appropriate value such that
x == y implies both that x is y and hash(x) == hash(y).
Source: Data model
The default is something like:
class OnlyExists:
def __eq__(self, other):
return False
def __hash__(self):
return id(self)
Because it's unequal to everything, instances can only be found by identity. Giving a minimal hash implementation (i.e. not just returning the same hash value for every instance) means that the instances don't all end up in the same "bucket", which would be a catastrophic collision and mean all dictionary/set searches fall to O(n).
>>> class OnlyExists:
... pass
...
>>> a = OnlyExists()
>>> b = OnlyExists()
>>> s = {a, b}
>>> len(s)
2
>>> a in s
True
>>> b in s
True
>>> OnlyExists() in s
False

Why is `int.__eq__(other)` a working comparison?

The following code works with Python 2.7:
>>> class Derived(int):
... def __eq__(self, other):
... return int.__eq__(other)
...
>>> Derived(12) == 12.0
True
>>> Derived(12) == 13
False
I do not understand, why it works, given that the self attribute is not explicitly given to int.__eq__() method call.
[EDIT]
Answers so far suggested, that it is about returning NotImplemented by self.__eq__(other) and thus calling other.__eq__(self). Then Derived(12) == Derived(12) I expect to be an infinitive recursion, which is not the case:
>>> Derived(12) == Derived(12)
True
It works because int.__eq__(<something>) returns NotImplemented and when that happens it results in a call to other.__eq__(self) and that's what is returning True and False here.
Demo:
class Derived(int):
def __eq__(self, other):
print self, other
print int.__eq__(other)
print other.__eq__(self)
return int.__eq__(other)
>>> Derived(12) == 12.0
12 12.0
NotImplemented
True
True
>>> Derived(12) == 13.0
12 13.0
NotImplemented
False
False
From NotImplemented
's docs:
Special value which should be returned by the binary special methods
(e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to
indicate that the operation is not implemented with respect to the
other type; may be returned by the in-place binary special methods
(e.g. __imul__(), __iand__(), etc.) for the same purpose. Its
truth value is true.
Note When NotImplemented is returned, the interpreter will then try
the reflected operation on the other type, or some other fallback,
depending on the operator. If all attempted operations return
NotImplemented, the interpreter will raise an appropriate exception.
What happens when both __eq__ return NotImplemented?
The behaviour is different in Python 2 and 3.
In Python 2 it falls back to __cmp__ method first and integers have __cmp__ method in Python 2. It has been removed in Python 3.
As per Python 2 docs if nothing is found it ultimately falls back to identity comparison:
If no __cmp__(), __eq__() or __ne__() operation is defined, class
instances are compared by object identity (“address”)
class Derived(int):
def __eq__(self, other):
print ("Inside __eq__")
return NotImplemented
def __cmp__(self, other):
print ("Inside __cmp__ finally")
return True
>>> Derived(12) == Derived(12)
Inside __eq__
Inside __eq__
Inside __cmp__ finally
False
Not let's define a class with no method defined:
class Derived(object):
pass
>>> Derived() == Derived()
False
>>> d = Derived()
>>> d == d # Same objects.
True
Python 3 doesn't have __cmp__ method anymore but it seems to be falling back to identity now. And it seems it is not documented either.
# Python 3.5
>>> Derived() == Derived()
False
>>> d = Derived()
>>> d == d
True
When mixing float with an integer type, there's no good uniform approach.
https://github.com/python/cpython/blob/2.7/Objects/floatobject.c#L401-L417
P.S.
How int() object using "==" operator without __eq__() method in python2?
In Python 2.7, if you call int.__eq__ it always returns NotImplemented. Example:
>>> int.__eq__(12.0)
NotImplemented
When you use the == operator it will attempt to run the __eq__ method on the left argument, and if it gets NotImplemented it will return the result of the __eq__ method from the argument on the right.
In your example for Derived(12) == 12.0, the interpreter first tries Derived(12).__eq__(12.0), and gets NotImplemented. It then runs the __eq__ method on the float number 12.0 and gets True.
In the case of your Derived(12) == Derived(12) example, what's likely happening is that since both objects return NotImplemented for their __eq__ methods, and since Derived inherits from int, the interpreter falls back to using the cmp builtin behavior for int (according to this answer, which is linked-to in another answer to your question).
Here's an example that illustrates your case:
class Derived(int):
def __eq__(self, other):
print 'Doing eq'
return NotImplemented
def __cmp__(self, other):
print 'doing cmp'
return 0 # contrived example - don't do this
>>> Derived(12) == Derived(12)
doing eq
doing eq
doing cmp
True

Overriding __eq__ in Python: How does switching of arguments order happen? [duplicate]

Since Python does not provide left/right versions of its comparison operators, how does it decide which function to call?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
This seems to call both __eq__ functions.
I am looking for the official decision tree.
The a == b expression invokes A.__eq__, since it exists. Its code includes self.value == other. Since int's don't know how to compare themselves to B's, Python tries invoking B.__eq__ to see if it knows how to compare itself to an int.
If you amend your code to show what values are being compared:
class A(object):
def __eq__(self, other):
print("A __eq__ called: %r == %r ?" % (self, other))
return self.value == other
class B(object):
def __eq__(self, other):
print("B __eq__ called: %r == %r ?" % (self, other))
return self.value == other
a = A()
a.value = 3
b = B()
b.value = 4
a == b
it will print:
A __eq__ called: <__main__.A object at 0x013BA070> == <__main__.B object at 0x013BA090> ?
B __eq__ called: <__main__.B object at 0x013BA090> == 3 ?
When Python2.x sees a == b, it tries the following.
If type(b) is a new-style class, and type(b) is a subclass of type(a), and type(b) has overridden __eq__, then the result is b.__eq__(a).
If type(a) has overridden __eq__ (that is, type(a).__eq__ isn't object.__eq__), then the result is a.__eq__(b).
If type(b) has overridden __eq__, then the result is b.__eq__(a).
If none of the above are the case, Python repeats the process looking for __cmp__. If it exists, the objects are equal iff it returns zero.
As a final fallback, Python calls object.__eq__(a, b), which is True iff a and b are the same object.
If any of the special methods return NotImplemented, Python acts as though the method didn't exist.
Note that last step carefully: if neither a nor b overloads ==, then a == b is the same as a is b.
From https://eev.ee/blog/2012/03/24/python-faq-equality/
Python 3 Changes/Updates for this algorithm
How is __eq__ handled in Python and in what order?
a == b
It is generally understood, but not always the case, that a == b invokes a.__eq__(b), or type(a).__eq__(a, b).
Explicitly, the order of evaluation is:
if b's type is a strict subclass (not the same type) of a's type and has an __eq__, call it and return the value if the comparison is implemented,
else, if a has __eq__, call it and return it if the comparison is implemented,
else, see if we didn't call b's __eq__ and it has it, then call and return it if the comparison is implemented,
else, finally, do the comparison for identity, the same comparison as is.
We know if a comparison isn't implemented if the method returns NotImplemented.
(In Python 2, there was a __cmp__ method that was looked for, but it was deprecated and removed in Python 3.)
Let's test the first check's behavior for ourselves by letting B subclass A, which shows that the accepted answer is wrong on this count:
class A:
value = 3
def __eq__(self, other):
print('A __eq__ called')
return self.value == other.value
class B(A):
value = 4
def __eq__(self, other):
print('B __eq__ called')
return self.value == other.value
a, b = A(), B()
a == b
which only prints B __eq__ called before returning False.
Note that I also correct a small error in the question where self.value is compared to other instead of other.value - in this comparison, we get two objects (self and other), usually of the same type since we are doing no type-checking here (but they can be of different types), and we need to know if they are equal. Our measure of whether or not they are equal is to check the value attribute, which must be done on both objects.
How do we know this full algorithm?
The other answers here seem incomplete and out of date, so I'm going to update the information and show you how how you could look this up for yourself.
This is handled at the C level.
We need to look at two different bits of code here - the default __eq__ for objects of class object, and the code that looks up and calls the __eq__ method regardless of whether it uses the default __eq__ or a custom one.
Default __eq__
Looking __eq__ up in the relevant C api docs shows us that __eq__ is handled by tp_richcompare - which in the "object" type definition in cpython/Objects/typeobject.c is defined in object_richcompare for case Py_EQ:.
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue #1393. */
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
So here, if self == other we return True, else we return the NotImplemented object. This is the default behavior for any subclass of object that does not implement its own __eq__ method.
How __eq__ gets called
Then we find the C API docs, the PyObject_RichCompare function, which calls do_richcompare.
Then we see that the tp_richcompare function, created for the "object" C definition is called by do_richcompare, so let's look at that a little more closely.
The first check in this function is for the conditions the objects being compared:
are not the same type, but
the second's type is a subclass of the first's type, and
the second's type has an __eq__ method,
then call the other's method with the arguments swapped, returning the value if implemented. If that method isn't implemented, we continue...
if (!Py_IS_TYPE(v, Py_TYPE(w)) &&
PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
(f = Py_TYPE(w)->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Next we see if we can lookup the __eq__ method from the first type and call it.
As long as the result is not NotImplemented, that is, it is implemented, we return it.
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Else if we didn't try the other type's method and it's there, we then try it, and if the comparison is implemented, we return it.
if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
Finally, we get a fallback in case it isn't implemented for either one's type.
The fallback checks for the identity of the object, that is, whether it is the same object at the same place in memory - this is the same check as for self is other:
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
Conclusion
In a comparison, we respect the subclass implementation of comparison first.
Then we attempt the comparison with the first object's implementation, then with the second's if it wasn't called.
Finally we use a test for identity for comparison for equality.

overriding __cmp__ python function

Hi I am overriding __cmp__ . If the second object passed is None, or if it is not an instance of someClass, then it returns -1.
I don't understand what exactly is happening here.
class someClass():
def __cmp__(self, obj):
if obj == None:
return -1
if not isinstance(obj, someClass):
return -1
My test function:
def test_function(self):
obj1 = someClass()
self.assertTrue(obj1 < None)
# I get true.
self.assertTrue(obj1 > None)
# I get failure as False is returned.
Could anyone please explain to me:
What are the return values?
How is it deciding whether it will return True or False when the comparison signs are changed?
The convention for __cmp__ is:
a < b : return -1
a = b : return 0
a > b : return 1
This of course makes only sense if both a and b are of compatible types, say numbers. If you have a 'corner case', where a or b is either None or incompatible (not instanceof), you should report an error, as this is a programming error in the use of the comparison operators on your someClass instance.
It is possible to implement any behaviour with __cmp__, but a comparison with None the way described by the OP will eventually lead to strange behaviour and bugs.
see also: __lt__ instead of __cmp__
http://docs.python.org/reference/datamodel.html#object.__cmp__
When the obj is None, your program will return -1, while returning a negative integer means self < obj, so obj1 < None is True, and obj1 > None is false.
If you look at the python documentation, you'll see that the cmp function return -1 if self < other.
Since __cmp__(obj, None) == -1, it assumed that obj < None.
My guess if __cmp__(obj, None) should return 1 as any object is superior to no object :)

Is there a significant difference between: if not a == 'bar' and if a != 'bar'?

Is this just two ways to write the same code? Is there any functional difference I should be aware of?
>>> a = 'foo'
>>> if not a == 'bar':
... 'its not'
...
'its not'
>>> if a != 'bar':
... 'its not'
...
'its not'
In python, to check whether or not an object is equal or not equal to another object, special functions are called. __eq__ is called to check ==, while __ne__ is called to check !=
In general, an object could define __ne__ differently than __eq__.
E.g.
class Junk(object):
def __ne__(self, other):
return False
def __eq__(self, other):
return False
j = Junk()
print not j == 1
print j != 1
This yields:
True
False
However, this would be especially evil... You usually should never have to worry about this.
not a == b gets translated to a call to not a.__eq__(b), while a != b gets translated to a call to a.__ne__(b). For the most part (pretty much every normal object I can think of), __ne__ is defined as def __ne__(self, other): not self.__eq__(other), so there's no functional difference. However, you could easily create a psychotic object that was both equal and not equal to other values, just by overriding __ne__ in the right way (though I can't think of a case where that would make sense right now).
On the flip side, the builtin objects probably implement a != b in manner that's slightly faster than not a == b, but probably not by any noticable amount.

Categories

Resources