Python字节码函数调用传递自我

时间:2017-07-13 08:07:23

标签: python python-internals

我试图理解字节码是如何工作的。

a.func()是函数调用。相应的字节码大致为LOAD_GLOBAL aLOAD_ATTR attr,然后是CALL_FUNCTION,带有0个参数。

如果a是一个模块,这完全没问题。但是如果a是一个对象,它必须传递对象实例本身。由于Python在编译时无法知道a是模块还是对象,因此无论a的类型如何,字节码都是相同的。但是如果self是一个对象,运行时系统如何处理func作为a的第一个参数?在字节码级别下面是否有一些特殊处理说"如果在一个对象上调用它,则将该对象作为第一个参数"?

3 个答案:

答案 0 :(得分:2)

字节码不必因不同的对象类型而异。对象类型本身负责管理绑定行为。这包含在descriptor protocol

简而言之,LOAD_ATTR代理通过object.__getattribute__ hook属性访问对象:

  

无条件调用以实现类实例的属性访问。

对于模块,__getattribute__只需查找__dict__命名空间中的名称并返回它。但是对于类和元类,如果属性支持,实现将调用描述符协议。函数支持描述符协议,并在询问时返回绑定方法

>>> class Foo:
...     def method(self): pass
...
>>> Foo().method  # access on an instance -> binding behaviour
<bound method Foo.method of <__main__.Foo object at 0x107155828>>
>>> Foo.method    # access on the class, functions just return self when bound here
<function Foo.method at 0x1073702f0>
>>> Foo.method.__get__(Foo(), Foo)  # manually bind the function
<bound method Foo.method of <__main__.Foo object at 0x107166da0>>

此绑定行为也是propertyclassmethodstaticmethod对象工作方式的基础(后者通过返回函数本身来实现函数的绑定行为)。

答案 1 :(得分:1)

LOAD_ATTR通过描述符(https://docs.python.org/2/howto/descriptor.html)完成魔术。

假设a是A类的对象: 在python函数中是描述符。当你执行a.func时,实际上它返回A.func,这是描述符对象(未绑定的函数)。然后&#34;升级&#34;本身绑定函数(A.func.__get__被调用)。必须首先明确地给出未绑定函数的自参数。绑定函数已经记住了自我论证&#34;内部&#34;本身。

在python模块中是一个对象并使用完全相同的机制。

答案 2 :(得分:1)

简而言之,a.func已经知道它绑定了哪个对象,因此不需要显式的self(它已经知道self是什么):

>>> a.func
<bound method A.func of <__main__.A object at 0x10e810a10>>

将此与A.func(其中A为类)对比:

>>> A.func
<unbound method A.func>

调用A.func确实需要明确的self

>>> A.func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method func() must be called with A instance as first argument (got nothing instead)
>>> A.func(a)
>>>

或者,在字节码中:

          0 LOAD_GLOBAL              0 (A)
          3 LOAD_ATTR                1 (func)
          6 LOAD_GLOBAL              2 (a)
          9 CALL_FUNCTION            1
         12 POP_TOP             

(注意额外的LOAD_GLOBAL。)

Python Language Reference(搜索im_self__self__)解释了绑定与未绑定方法的机制。