Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing object methods leads to different results in 3.8

Consider this simple class:

class A:
    def method(self): pass
    def __eq__(self, other): return True

Now if I create two instances of the class and compare their 'method' attributes, I get different results in Python 3.7 and 3.8:

meth1 = A().method
meth2 = A().method
print(meth1 == meth2)  # True in 3.7, False in 3.8

What's going on here? Why are the methods equal in 3.7 but not in 3.8? And what does this have to do with __eq__?

like image 323
planetp Avatar asked Nov 12 '19 16:11

planetp


People also ask

Why is the value of two objects in comparison not 1?

By comparing two objects, the value of those objects is not 1. Rather it is their memory addresses in the stack that are different since both objects were created using the new operator. If we had assigned a to b, then we would've had a different result:

How to compare two objects in Java?

Every class in java has one parent class that is Object class and it has equals () method to compare two any objects. This program compiles and executes successfully. When the e1.equals (e2) method is invoked it internally compares two object references but not the values. So it has to have a different address.

Can comparator<commonab> compare objects of different types?

Finally, a Comparator<CommonAB> will be able to compare objects of both types. The Comparator will access only the methods of the interface. It won't care if it's comparing two As, two Bs or an A and a B.

How do you compare models across multiple test images?

The most common approach to end with a single value allowing for model comparison is calculating Average Precision (AP) – calculated for a single object class across all test images, and finally mean Average Precision (mAP) – a single value that can be used to compare models handling detection of any number of object classes.


1 Answers

What happened is this commit based on issue 16171610 (and this discussion on python-dev).

With these (selected) comments:

It seems unlogical to me that whether or not the instance methods of two different instances are equal or not depends on the equality of the instance.

followed by

All in all I think that this part was an accident and never designed;

and

I think it makes little sense that the equality test for the instance methods takes the equality of the instances into account. Imho, this behaviour is inconsistent with the principle of no surprises. The correct behaviour (again imho of course) is that instance methods only compare equal to the same instance method of the same instance, where 'same instance' is based on 'is' not on '=='.

and

This change can be considered as a bugfix, but since it can break the user code (unlikely), it may be safer to merge it only in 3.8 and expose as a new feature.

So this seems to be considered a bugfix/feature because bound methods should only be equal if they are bound on the same instance, not if the instances are considered equal. In Python <= 3.7 the bound method equality calls the equivalent of instance1 == instance2 (thus calling your __eq__) of the instance while in Python 3.8 it checks if instance1 is instance2.


The corresponding changelog item can be found in section "Python 3.8.0 alpha 1" - it's a long list of items, so I included a copy here:

  • bpo-1617161: The hash of BuiltinMethodType instances (methods of built-in classes) now depends on the hash of the identity of __self__ instead of its value. The hash and equality of ModuleType and MethodWrapperType instances (methods of user-defined classes and some methods of built-in classes like str.__add__) now depend on the hash and equality of the identity of __self__ instead of its value. MethodWrapperType instances no longer support ordering.
like image 105
MSeifert Avatar answered Sep 21 '22 14:09

MSeifert