我尝试了一些关于绑定(bind)和非绑定(bind)方法的代码。当我们调用它们时,我认为它们都会返回对象。但是当我使用 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
分配给两个变量,#3 和 #4 会返回不同的 id。
我认为#3和#4表明它们不是同一个对象,而是#1和#2...
绑定(bind)方法的id和未绑定(bind)方法的id有什么区别?
最佳答案
每当您通过 instance.name
(在 Python 2 中为 class.name
)查找方法时,都会重新创建方法对象。 Python 使用 descriptor protocol每次都将函数包装在方法对象中。
因此,当您查找 id(C.foo)
时,会创建一个新的方法对象,您检索其 id(内存地址),然后 再次丢弃该方法对象。然后您查找 id(cobj.foo)
,这是一个创建的新方法对象,它重新使用现在释放的内存地址,您会看到相同的值。然后,该方法再次被丢弃(当引用计数降至 0 时收集垃圾)。
接下来,您将对 C.foo
未绑定(bind)方法的引用存储在变量中。现在内存地址没有被释放(引用计数是 1,而不是 0),并且您通过查找必须使用的 cobj.foo
创建一个 second 方法实例一个新的内存位置。因此,您会得到两个不同的值。
Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same
id()
value.CPython implementation detail: This is the address of the object in memory.
强调我的。
您可以通过类的 __dict__
属性使用对函数的直接引用来重新创建方法,然后调用 __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 中,整个未绑定(bind)/绑定(bind)方法的区别已被删除;你会得到一个函数,在你得到一个未绑定(bind)的方法之前,你会得到一个方法,否则,一个方法是总是绑定(bind)的:
>>> 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
精确替换当前 LOAD_ATTRIBUTE
- CALL_FUNCTION
操作码对的操作码对,以避免每次都创建新的方法对象。此优化将 instance.foo()
的执行路径从 type(instance).__dict__['foo'].__get__(instance, type(instance))()
使用 type(instance).__dict__['foo'](instance)
,因此“手动”将实例直接传递给函数对象。
关于python - 绑定(bind)和未绑定(bind)方法对象的 id() --- 有时不同对象相同,有时相同对象不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13348031/