我试图了解字节码的工作原理。a.func()
是一个函数调用。对应的字节码大致是 LOAD_GLOBAL a
、 LOAD_ATTR attr
和 CALL_FUNCTION
,参数为 0。
如果 a
是一个模块,这完全没问题。但是如果 a
是一个对象,它必须传递对象实例本身。由于 Python 在编译时无法知道 a
是模块还是对象,因此无论 a
的类型如何,字节码自然是相同的。但是如果 self
是一个对象,运行时系统如何将 func
作为 a
的第一个参数处理?字节码级别以下是否有一些特殊处理,表示“如果在对象上调用它,则将对象作为第一个参数”?
最佳答案
字节码不必因不同的对象类型而变化。管理绑定(bind)行为是对象类型本身的责任。这在 descriptor protocol 中有介绍。
简而言之,LOAD_ATTR
通过 object.__getattribute__
hook 委托(delegate)对对象的属性访问:
对于模块,__getattribute__
只是在 __dict__
命名空间中查找名称并返回它。但是对于类和元类,如果属性支持,则实现将调用描述符协议(protocol)。函数支持描述符协议(protocol)并在被询问时返回绑定(bind)方法:
>>> 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>>
这种绑定(bind)行为也是
property
、 classmethod
和 staticmethod
对象如何工作的基础(后者通过返回函数本身来中和函数的绑定(bind)行为)。关于Python字节码函数调用传递自我,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45074917/