我试过一点。通过检查类或实例的 __dict__,我可以看到一些方法具有 function 类型和一些 绑定(bind)方法。实验很乱,我想不出下面的问题。
在 Python 3 中,类或实例的方法之间有什么区别,哪些是“函数”,哪些是“绑定(bind)方法”?
它们分别是如何创建的?
它们可以同时在类和实例上调用吗?他们都会被隐含地给出一个实例作为他们的第一个参数吗?
“绑定(bind)方法”是类的属性还是类的实例?
谢谢。
请您参考如下方法:
这个答案将是非常技术性的,但我希望它仍然是可以理解的。问题是它需要描述符协议(protocol)的知识才能理解 Python 中的方法是如何工作的。
Python 3 中的所有函数都是 descriptors ,准确地说它们是非数据描述符。这意味着他们实现了 __get__ 方法 - 但没有实现 __set__ 方法。
这很有趣,因为如果在类或实例中查找描述符,它们(几乎)可以做任何事情。
根据Pythons data model中__get__方法的定义:
object.__get__(self, instance, owner)Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access).
owneris always the owner class, whileinstanceis the instance that the attribute was accessed through, orNonewhen the attribute is accessed through theowner. This method should return the (computed) attribute value or raise anAttributeErrorexception.
那么这与 function 和 bound_method 之间的区别有什么关系呢?
这很简单,通过 __get__ 使用 instance=None 访问的函数将返回自身:
>>> def func(x): return x
>>> func.__get__(None, object)
<function __main__.func>
>>> func.__get__(None, object) is func
True
如果使用 not-None 实例访问,它将是一个 bound_method:
>>> func.__get__(object())
<bound method func of <object object at 0x00000155614A0610>>
它基本上只是 func 的包装器,其中存储了实例:
>>> m = func.__get__(object())
>>> m.__self__ # stored instance
<object at 0x155614a0650>
>>> m.__func__ # stored function
<function __main__.func>
然而,当被调用时,它会将实例作为第一个参数传递给包装函数:
>>> m()
<object at 0x155614a0650>
因此,绑定(bind)方法会将实例作为第一个参数传递,而函数则不会(它们需要所有属性)。
因此,当您查看一个类时,所有普通 方法都将显示为函数,而实例上的所有普通 方法都是绑定(bind)方法。
为什么我要提到正常方法?因为您可以定义任意描述符。例如,Python 内置函数已经包含几个异常:
类方法静态方法property(这实际上是一个数据描述符,所以我将在下面的讨论中忽略它)
classmethod 将显示为 bound method 即使在类中查找也是如此。那是因为它们意味着可以在类上调用并将类传递给函数,无论它们是在类上还是在实例上调用:
class Test(object):
@classmethod
def func(x):
return x
>>> Test.func
<bound method Test.func of <class '__main__.Test'>>
>>> Test().func
<bound method Test.func of <class '__main__.Test'>>
staticmethod 总是显示为函数,因为它们从不向函数传递任何额外的东西:
class Test(object):
@staticmethod
def func(x):
return x
>>> Test().func
<function __main__.Test.func>
>>> Test.func
<function __main__.Test.func>
因此很容易在类中看到 bound method(例如 classmethod),同样也可以找到普通的 function实例上的 s(例如 staticmethods)。
