我有一个错误,在使用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
答案 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