我做了一点实验。通过检查类或实例的__dict__
,我可以看到某些方法具有类型function
和一些bound method
。实验很乱,我无法解决以下问题。
在Python 3中,类或实例的方法之间有什么区别,它们是" function"哪些是"约束方法"?
他们是如何分别创作的?
它们都可以在类和实例上调用吗?它们是否会被隐含地赋予实例作为第一个参数?
"约束方法"类的属性或类的实例?
感谢。
答案 0 :(得分:5)
这个答案非常技术性,但我希望它仍然可以理解。问题是需要知道描述符协议才能理解Python中的方法是如何工作的。
Python 3中的所有函数都是descriptors,准确地说它们是非数据描述符。这意味着他们实现了__get__
方法 - 但没有__set__
方法。
这很有趣,因为如果在类或实例上查找描述符,它们几乎可以做任何事情。
根据Pythons data model中__get__
方法的定义:
object.__get__(self, instance, owner)
调用以获取所有者类(类属性访问)或该类的实例(实例属性访问)的属性。
owner
始终是所有者类,而instance
是访问该属性的实例,或None
通过owner
访问该属性时。此方法应返回(计算的)属性值或引发AttributeError
异常。
那么这与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>
因此,bound method
s将实例作为第一个参数传递,而function
则不传递(它们需要所有属性)。
因此,当您查看某个类时,所有普通方法将显示为函数,而实例上的所有普通方法将为bound methods
。
为什么我提到普通的方法?因为您可以定义任意描述符。例如,Python内置函数已经包含几个例外:
classmethod
staticmethod
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
s),同样也可以在实例上找到正常的function
(例如{ {1}} S)。