python3:使用.__ get __()将类方法绑定到类实例,但是为什么呢?

etu*_*rdu 8 python methods monkeypatching descriptor python-3.x

我知道如果你想为一个类实例添加一个方法,你不能像这样做一个简单的赋值:

>>> def print_var(self): # method to be added
        print(self.var)
>>> class MyClass:
        var = 5
>>> c = MyClass()
>>> c.print_var = print_var
Run Code Online (Sandbox Code Playgroud)

这确实会导致print_var行为像正常的函数,所以self参数不具有他的典型含义:

>>> c.print_var
<function print_var at 0x98e86ec>
>>> c.print_var()
Traceback (most recent call last):
  File "<pyshell#149>", line 1, in <module>
    c.print_var()
TypeError: print_var() takes exactly 1 argument (0 given)
Run Code Online (Sandbox Code Playgroud)

为了让函数被认为是一个方法(即将它绑定到实例),我曾经使用过这段代码:

>>> import types
>>> c.print_var = types.MethodType(print_var, c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5
Run Code Online (Sandbox Code Playgroud)

但我发现它.__get__也可能用于此目的:

>>> c.print_var = print_var.__get__(c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5
Run Code Online (Sandbox Code Playgroud)

这里的问题是它只是有效,但我无法理解如何以及为什么.有关文档.__get__似乎没有多大帮助.

如果有人能澄清python的解释器的这种行为,我会很感激.

agf*_*agf 8

您正在寻找的信息在Descriptor HowTo指南中:

为了支持方法调用,函数包括__get__()在属性访问期间绑定方法的方法.这意味着所有函数都是非数据描述符,它们返回绑定或未绑定方法,具体取决于它们是从对象还是类调用.在纯Python中,它的工作原理如下:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj)
Run Code Online (Sandbox Code Playgroud)

所以真的没有什么奇怪的事情 - __get__函数对象的方法调用types.MethodType并返回结果.

  • 在 Python 3 中 `MethodType()` 只接受 2 个参数。 (2认同)
  • 事实上,它们是更新的。我建议您编辑答案 (2认同)
  • @drevicko 他并不是说 `__get__` 改变了,他是说 `MethodType` 现在只需要两个参数——它过去需要三个参数。我两年前更新了答案以反映这一点。 (2认同)