问题
I had a bug where I was relying on methods being equal to each other when using is
. It turns out that's not the case:
>>> class What(object):
def meth(self):
pass
>>> What.meth is What.meth
False
>>> inst = What()
>>> inst.meth is inst.meth
False
Why is that the case? It works for regular functions:
>>> def func():
pass
>>> func is func
True
回答1:
Method objects are created each time you access them. Functions act as descriptors, returning a method object when their .__get__
method is called:
>>> 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>>
Use ==
equality testing instead.
Two methods are equal if their .im_self
and .im_func
attributes are identical. If you need to test that the methods represent the same underlying function, test their im_func
attributes:
>>> 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
回答2:
Martijn is right that a new Methods are objects generated by .__get__
so their address pointers don't equate with an is
evaluation. Note that using ==
will evaluate as intended in 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
Note however that methods referenced from an instance do not equate to those referenced from class because of the self reference carried along with the method from an instance.
>>> t = Test()
>>> t.meth is Test.meth
False
>>> t.meth == Test.meth
False
In Python 3.3 the is
operator for methods more often behaves the same as the ==
so you get the expected behavior instead in this example. This results from both __cmp__
disappearing and a cleaner method object representation in Python 3; methods now have __eq__
and references are not built-on-the-fly objects, so the behavior follows as one might expect without Python 2 expectations.
Python3.3
>>> Test.meth is Test.meth
True
>>> Test.meth == Test.meth
True
>>> Test.meth.__eq__(Test.meth)
True
来源:https://stackoverflow.com/questions/15977808/why-dont-methods-have-reference-equality