python绑定和未绑定的方法对象
我试过一些关于绑定和非绑定方法的代码。 当我们打电话给他们时,我想他们俩都会返回对象。 但是当我使用id()
获取一些信息时,它返回一些我不明白的东西。
IDE:Eclipse插件:pydev
Class C(object): def foo(self): pass cobj = C() print id(C.foo) #1 print id(cobj.foo) #2 a = C.foo b = cobj.foo print id(a) #3 print id(b) #4
和输出是..
5671672 5671672 5671672 5669368
为什么#1和#2返回相同的ID,是不是他们不同的对象? 如果将C.foo
和conj.foo
分配给两个variables,#3和#4将返回不同的ID。
我认为#3和#4显示它们不是同一个对象,但#1和#2 …
绑定方法的id和unbound方法有什么区别?
每当通过class.name
或instance.name
查找方法时,方法对象都会被创build为新的。 Python每次使用描述符协议将函数包装在方法对象中。
所以,当你查找id(C.foo)
,会创build一个新的方法对象,检索它的id(内存地址),然后再丢弃方法对象 。 然后你查找id(cobj.foo)
,一个新创build的方法对象,重新使用现在释放的内存地址,你看到相同的值。 然后,该方法再次被丢弃(当参考计数下降到0时收集垃圾)。
接下来,您将一个对C.foo
unbound方法的引用存储在一个variables中。 现在内存地址不被释放(引用计数为1,而不是0),并且通过查找cobj.foo
来创build第二个方法实例,该实例必须使用新的内存位置。 因此你得到两个不同的值。
请参阅id()
的文档 :
返回一个对象的“身份”。 这是一个整数(或长整数),在整个生命周期中保证它是唯一的,并且是常量。 两个具有非重叠生命周期的对象可能具有相同的
id()
值 。CPython实现细节 :这是内存中对象的地址。
强调我的。
您可以通过类的__dict__
属性直接引用函数来重新创build方法,然后调用__get__
描述符方法 :
>>> class C(object): ... def foo(self): ... pass ... >>> C.foo <unbound method C.foo> >>> C.__dict__['foo'] <function foo at 0x1088cc488> >>> C.__dict__['foo'].__get__(None, C) <unbound method C.foo> >>> C.__dict__['foo'].__get__(C(), C) <bound method C.foo of <__main__.C object at 0x1088d6f90>>
请注意,在Python 3中,整个未绑定/绑定方法的区别已被删除; 你得到一个函数,在你得到一个未绑定的方法之前,否则,一个方法总是被绑定的方法:
>>> C.foo <function C.foo at 0x10bc48dd0> >>> C.foo.__get__(None, C) <function C.foo at 0x10bc48dd0> >>> C.foo.__get__(C(), C) <bound method C.foo of <__main__.C object at 0x10bc65150>>
添加到@Martijn Pieters的非常好的答案 :
In [140]: class C(object): def foo(self): pass .....: In [141]: c=C() In [142]: id(c.foo),id(C.foo) Out[142]: (149751844, 149751844) #so 149751844 is current free memory address In [143]: a=c.foo #now 149751844 is assigned to a In [144]: id(a) Out[144]: 149751844 #now python will allocate some different address to c.foo and C.foo In [145]: id(c.foo),id(C.foo) # different address used this time,and # that address is freed after this step Out[145]: (149752284, 149752284) #now 149752284 is again free, as it was not allocated to any variable In [146]: b=C.foo #now 149752284 is allocated to b In [147]: id(b) Out[147]: 149752284 In [148]: c.foo is C.foo #better use `is` to compare objects, rather than id() Out[148]: False