我有这段代码:
class ABC:
def test():
print('Hi there')
ABC.test()
哪个输出:
Hi there
这失败了:
ABC().test()
TypeError: test() takes 0 positional arguments but 1 was given
# Makes sense
我们知道,当我们调用classmethod
之类的<classname>.<methodname>()
时,该类将作为参数隐式传递给它,但是test
这里没有任何参数。
为什么由于意外的参数而看不到TypeError
?该类不是作为参数传递给test
吗?
答案 0 :(得分:3)
什么都不会传递给test()
,因为函数在访问类时不会绑定任何东西。它仍然是 unbound ,您将获得原始功能:
>>> class ABC:
... def test():
... print('Hi there')
...
>>> ABC.test
<function ABC.test at 0x1082706c0>
如果您传入正确数量的参数,则可以直接调用函数。此处为0,因此ABC.test()
成功。
它不是classmethod
,需要用@classmethod
装饰(或产生classmethod
对象并将其存储为类的属性),然后访问属性将函数绑定到类对象,从而生成绑定的method
:
>>> class ABC:
... @classmethod
... def test():
... print('Hi there')
...
>>> ABC.test
<bound method ABC.test of <class '__main__.ABC'>>
调用此方法将导致异常:
>>> ABC.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test() takes 0 positional arguments but 1 was given
也可以绑定函数,但仅当在类的实例上访问时才可以。 function
和classmethod
对象均实现descriptor protocol,并且在类和实例上访问属性将触发描述符上的__get__
方法。但是在这种情况下,只有classmethod
个对象会返回绑定方法,而函数只会返回自身。
具体来说,将descriptor __get__
method传递给None
作为第一个参数,当属性访问在类上时要绑定到的对象,以及在实例上访问时要实例的对象。 classmethod().__get__()
忽略实例参数,并生成一个绑定到第二个参数(owner
)的方法对象。当第一个参数为self
时,函数将返回None
,否则将返回绑定到实例的方法对象:
>>> def foo(boundto='nothing'):
... print(f'Bound to {boundto}')
...
>>> foo.__get__('instance', 'owner')()
Bound to instance
>>> foo.__get__(None, 'owner')()
Bound to nothing
>>> classmethod(foo).__get__('instance', 'owner')()
Bound to owner
>>> classmethod(foo).__get__(None, 'owner')()
Bound to owner