绑定方法对象和未绑定方法对象的id()---对于不同的对象有时是相同的,对于相同的对象有时是不同的 [英] id()s of bound and unbound method objects --- sometimes the same for different objects, sometimes different for the same object
问题描述
我尝试了一些关于绑定和非绑定方法的代码.当我们调用它们时,我认为它们都会返回对象.但是,当我使用id()
获取一些信息时,它返回的内容我并不理解.
I've tried some code about bound and unbound methods. When we call them, I think both of them would return objects. But when I use id()
for getting some information, it returns something I don't understand.
IDE:Eclipse
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
分配给两个变量,则#3和#4返回不同的ID.
Why do #1 and #2 return the same id? Aren't they different objects? And if we assign C.foo
and conj.foo
to two variables, #3 and #4 return the different id.
我认为#3和#4表明它们不是同一对象,而是#1和#2 ...
I think #3 and #4 show that they are not the same object, but #1 and #2...
绑定方法的ID和未绑定方法的ID有什么区别?
What is the difference between the id of bound method, and an unbound method?
推荐答案
每当通过instance.name
(在Python 2,class.name
)中查找方法时,都会重新创建该方法对象. Python使用描述符协议将函数包装在方法中每次都反对.
Whenever you look up a method via instance.name
(and in Python 2, class.name
), the method object is created a-new. Python uses the descriptor protocol to wrap the function in a method object each time.
因此,当您查找id(C.foo)
时,将创建一个新的方法对象,您将检索其ID(内存地址),然后再次丢弃该方法对象.然后,您查找id(cobj.foo)
,这是一个创建的新方法对象,该对象重新使用现在释放的内存地址,并且看到相同的值.然后再次丢弃该方法(当引用计数降至0时收集垃圾).
So, when you look up id(C.foo)
, a new method object is created, you retrieve its id (a memory address), then discard the method object again. Then you look up id(cobj.foo)
, a new method object created that re-uses the now freed memory address and you see the same value. The method is then, again, discarded (garbage collected as the reference count drops to 0).
接下来,您将对C.foo
未绑定方法的引用存储在变量中.现在不释放内存地址(引用计数为1,而不是0),然后通过查找必须使用新内存位置的cobj.foo
创建 second 方法实例.这样,您将获得两个不同的值.
Next, you stored a reference to the C.foo
unbound method in a variable. Now the memory address is not freed (the reference count is 1, instead of 0), and you create a second method instance by looking up cobj.foo
which has to use a new memory location. Thus you get two different values.
有关id()
,请参见文档:
See the documentation for id()
:
返回对象的身份".这是一个整数(或长整数),在该对象的生存期内,此整数保证是唯一且恒定的. 两个具有非重叠生存期的对象可能具有相同的
id()
值 .
CPython实现细节:这是对象在内存中的地址.
CPython implementation detail: This is the address of the object in memory.
强调我的.
您可以通过类的__dict__
属性使用对函数的直接引用来重新创建方法,然后调用
You can re-create a method using a direct reference to the function via the __dict__
attribute of the class, then calling the __get__
descriptor method:
>>> 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中,取消了整个未绑定/绑定方法的区分;您将获得一个函数,在此之前,您将获得一个未绑定的方法,否则将获得一个方法,否则该方法将始终绑定 :
Note that in Python 3, the whole unbound / bound method distinction has been dropped; you get a function where before you'd get an unbound method, and a method otherwise, where a method is always bound:
>>> 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>>
此外,Python 3.7添加了新的 LOAD_METHOD
- CALL_METHOD
替换当前<精确地对c15>-CALL_FUNCTION
操作码进行配对,以避免每次都创建一个新的方法对象.这种优化将instance.foo()
的执行路径从type(instance).__dict__['foo'].__get__(instance, type(instance))()
转换为type(instance).__dict__['foo'](instance)
,因此手动"将实例直接传递给功能对象.
Furthermore, Python 3.7 adds a new LOAD_METHOD
- CALL_METHOD
opcode pair that replaces the current LOAD_ATTRIBUTE
- CALL_FUNCTION
opcode pair precisely to avoid creating a new method object each time. This optimisation transforms the executon path for instance.foo()
from type(instance).__dict__['foo'].__get__(instance, type(instance))()
with type(instance).__dict__['foo'](instance)
, so 'manually' passing in the instance directly to the function object.
这篇关于绑定方法对象和未绑定方法对象的id()---对于不同的对象有时是相同的,对于相同的对象有时是不同的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!