一尘不染

Python无法将绑定方法与其自身进行比较

python

我正在尝试编写一个测试,检查包含类的绑定方法的变量是否与对该方法的另一个引用相同。通常这不是问题,但是在同一类的另一个方法中完成时似乎不起作用。这是一个最小的示例:

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

我实际上使用的是assert而不是print,但是因为最终结果是相同的,所以这既不在这里也不在那里。测试运行如下:

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

结果是,False即使我期望是这样True。该问题在Python 3.5和Python 2.7(在Anaconda下运行)中均得到体现。

我知道绑定方法是通过执行类似操作获得的闭包TestClass.test_method.__get__(instance, type(instance))。但是,我希望self.sample_method已经是对这种闭包的引用,因此self.sample_methodinstance.sample_method表示相同的引用。

让我感到困惑的部分原因是pytest我正在运行的真实测试的输出(在上为PR工作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

如果我正确理解了输出,则实际比较(第一行)实际上是在比较相同的对象,但是不知何故出现了False。在这一点上,我唯一能想到的__get__就是实际上被两次调用,但是我既不知道为什么/在哪里/如何,也不知道如何解决它。


阅读 190

收藏
2021-01-20

共1个答案

一尘不染

它们不是相同的引用-表示两种方法的对象在内存中的位置不同:

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

更改为method_reference == self.sample_method将使断言通过。

自问题扩展以来的编辑:似乎是一个有缺陷的测试-
代码的实际功能可能不需要引用相同(is),而是相等(==)。因此,除了测试之外,您所做的更改可能不会破坏任何其他内容。

2021-01-20