绑定方法对象和未绑定方法对象的id()---对于不同的对象有时是相同的,对于相同的对象有时是不同的 [英] id()s of bound and unbound method objects --- sometimes the same for different objects, sometimes different for the same object

查看:118
本文介绍了绑定方法对象和未绑定方法对象的id()---对于不同的对象有时是相同的,对于相同的对象有时是不同的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了一些关于绑定和非绑定方法的代码.当我们调用它们时,我认为它们都会返回对象.但是,当我使用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.fooconj.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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆