为什么方法没有引用相等?

时间:2013-04-12 17:51:53

标签: python methods reference identity equality

我有一个错误,在使用is时我依赖的方法彼此相同。事实证明并非如此:

>>> class What(object):
    def meth(self):
        pass

>>> What.meth is What.meth
False
>>> inst = What()
>>> inst.meth is inst.meth
False

为什么会这样?它适用于常规功能:

>>> def func():
    pass

>>> func is func
True

2 个答案:

答案 0 :(得分:20)

每次访问时都会创建方法对象。函数充当descriptors,在调用.__get__方法时返回方法对象:

>>> What.__dict__['meth']
<function meth at 0x10a6f9c80>
>>> What.__dict__['meth'].__get__(None, What)
<unbound method What.meth>
>>> What.__dict__['meth'].__get__(What(), What)
<bound method What.meth of <__main__.What object at 0x10a6f7b10>>

改为使用==等式测试。

如果.im_self.im_func属性相同,则两种方法相同。如果您需要测试方法代表相同的基础函数,请测试它们的im_func属性:

>>> What.meth == What.meth     # unbound methods (or functions in Python 3)
True
>>> What().meth == What.meth   # unbound method and bound method
False
>>> What().meth == What().meth # bound methods with *different* instances
False
>>> What().meth.im_func == What().meth.im_func  # functions
True

答案 1 :(得分:1)

Martijn是正确的,新方法是由.__get__生成的对象,因此它们的地址指针不等同于is评估。请注意,使用==将按照Python 2.7中的预期进行评估。

Python2.7
class Test(object):
    def tmethod(self):
        pass

>>> Test.meth is Test.meth
False
>>> Test.meth == Test.meth
True

>>> t = Test()
>>> t.meth is t.meth
False
>>> t.meth == t.meth
True

但是请注意,从实例引用的方法不等于从类引用的方法,因为从实例中携带了自引用。

>>> t = Test()
>>> t.meth is Test.meth
False
>>> t.meth == Test.meth
False

在Python 3.3中,方法的is运算符通常与==的行为相同,因此您在此示例中获得了预期的行为。这是因为__cmp__消失了,Python 3中的方法对象表示更清晰;方法现在有__eq__,并且引用不是即时对象,因此行为遵循人们的预期而没有Python 2期望。

Python3.3
>>> Test.meth is Test.meth
True
>>> Test.meth == Test.meth
True
>>> Test.meth.__eq__(Test.meth)
True