Python cannot compare a bound method to itself

I am trying to write a test that checks if a variable holding a bound class method is the same as another reference to this method. This is usually not a problem, but it does not seem to work when executed in another method of the same class. Here is a minimal example:

class TestClass: def sample_method(self): pass def test_method(self, method_reference): print(method_reference is self.sample_method) 

I really use assert instead of print , but this is neither here nor there, since the end result is the same. The test is performed as follows:

 instance = TestClass() instance.test_method(instance.sample_method) 

The result is False , although I expect it to be True . The problem manifests itself in both Python 3.5 and Python 2.7 (works under Anaconda).

I understand that related methods are closures that get by doing something like TestClass.test_method.__get__(instance, type(instance)) . However, I would expect that self.sample_method already a reference to such a closure, so that self.sample_method and instance.sample_method represent the same link.

Part of what confuses me is the result of a real pytest test that I run (working on PR for matplotlib ):

 assert <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> is <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> E + where <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> = <matplotlib.ticker.TransformFormatter object at 0x7f0101077e10>.transform E + and <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> = <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>.transform1 

If I understand the conclusion correctly, the actual comparison (first line) really compares the same objects, but somehow False appears. The only thing I can imagine at this point is that __get__ is actually called twice, but I don’t know why / where / how, and how to get around it.

+5
source share
2 answers

They are not the same reference - objects representing two methods occupy different places in memory:

 >>> class TestClass: ... def sample_method(self): ... pass ... def test_method(self, method_reference): ... print(hex(id(method_reference))) ... print(hex(id(self.sample_method))) ... >>> instance = TestClass() >>> instance.test_method(instance.sample_method) 0x7fed0cc561c8 0x7fed0cc4e688 

Going to method_reference == self.sample_method will skip assert.

Change, since the question was expanded: the test seems incorrect - probably, the actual functionality of the code does not require the same links ( is ), just equal ( == ). So your change probably didn't break anything but the test.

+5
source

Although the accepted answer is by no means incorrect, it seems to be noted that the methods are tied to attribute searches. In addition, the behavior of unbound methods changes between Python 2.X and Python 3.X.

 class A: def method(self): pass a = A() print(a.method is a.method) # False print(A.method is A.method) # Python 3.X: True, Python 2.X: False 
+3
source

Source: https://habr.com/ru/post/1263464/


All Articles