Python的callables是具有__call__
方法的对象。
它们大部分是时间函数,但也可能是类实例。
但事实上,函数确实有__call__
方法。
因此,__call__
方法也有__call__
方法。
以下REPL会话表明我们可以链接__call__
s:
>>> print
<built-in function print>
>>> print.__call__
<method-wrapper '__call__' of builtin_function_or_method object at 0x0000025E2D597F78>
>>> print.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x0000025E2F631438>
>>> print.__call__.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x0000025E2F5F85F8>
>>> print.__call__.__call__.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x0000025E2F725DA0>
......等等。 值得注意的是,所有这些方法都有不同的地址。 此外,它们都具有相同的行为:
>>> print("a")
a
>>> print.__call__("a")
a
>>> print.__call__.__call__("a")
a
>>> print.__call__.__call__.__call__("a")
那么,当我写print("a")
时,实际上是什么叫?
是print
还是print.__call__
?
如果我使用Foo
方法定义__call__
类,该怎么办?
此外,每个__call__
方法都有自己的不同的 __call__
方法怎么可能?
当我试图访问它们时,它们是否真的被创建了?
答案 0 :(得分:2)
与类上的方法类似,__call__
属性是在类型上定义的descriptor object,绑定到您查找的对象:
>>> type(print).__dict__['__call__']
<slot wrapper '__call__' of 'builtin_function_or_method' objects>
>>> type(print).__dict__['__call__'].__get__(print)
<method-wrapper '__call__' of builtin_function_or_method object at 0x10cc66f78>
>>> print.__call__
<method-wrapper '__call__' of builtin_function_or_method object at 0x10cc66f78>
绑定行为(通过__get__
方法)是生成的method-wrapper
实例知道如何将print
对象作为self
传递,就像实例传递一样您在自定义Python类上定义的方法。
所以是的,这意味着它们是按需创建的,因此将具有唯一的ID。否则它们只是同一类型的更多实例。
答案 1 :(得分:2)
print
是类builtin_function_or_method
的一个实例:
>>> type(print)
builtin_function_or_method
我们都知道(希望)当你访问一个方法时,实例被隐式地作为第一个参数传递:
>>> type(print).__call__(print, 10)
10
>>> print.__call__(10) # equivalent
10
这意味着当您访问函数的__call__
时,您实际上有类似绑定方法的内容。但是绑定方法(或者在本例中为methodwrappers)也是类型method_wrapper
:
>>> type(print.__call__)
method-wrapper
因此,当您访问该版本的__call__
方法时,它又会再次出现&#34; new&#34;约束方法。
>>> type(print.__call__).__call__(print.__call__, 10) # equivalent
10
此时它变为递归,因为方法包装器的方法只是另一个方法包装器实例:
>>> type(print.__call__.__call__)
method-wrapper
然而,所有这一切只会造成很多不必要的&#34;约束方法......