python - 绑定(bind)和未绑定(bind)方法对象的 id() --- 有时不同对象相同,有时相同对象不同

标签 python object methods

我尝试了一些关于绑定(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.fooconj.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 方法实例一个新的内存位置。因此,您会得到两个不同的值。

documentation for id() :

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/

相关文章:

python - 在代表 python 中大文件的大字符串上加速 re.sub()?

python - 为什么egrep的stdout没有通过管道?

python - 如何用以前的值替换列表中的无

c++ - 为什么我无法从文件中读取对象?

javascript - 根据单个属性从数组中获取唯一对象

java - 如何向对象ArrayList添加多个值?

python - 使用 urllib2 发出带有 headers 的 post 请求

c++ - 指针和方法的奇怪用法

java - 检查对象是否有Java中的方法?

java - Java 中的多态性以及从这些类创建对象