每当您尝试调用对象时,都会调用Python的魔术方法__call__
。因此Cls()()
等于Cls.__call__(Cls())
。
函数是Python中的第一类对象,这意味着它们只是可调用对象(使用__call__
)。但是,__call__
本身就是一个函数,因此它也有__call__
,它也有自己的__call__
,它也有自己的__call__
。
因此,Cls.__call__(Cls())
等于Cls.__call__.__call__(Cls())
,并且等同于Cls.__call__.__call__.__call__(Cls())
,依此类推。依此类推。
这个无限循环如何结束? __call__
如何实际执行代码?
答案 0 :(得分:9)
在幕后,Python中的所有调用都使用相同的机制,几乎所有调用都在CPython实现中达到相同的C函数。无论对象是具有__call__
方法的类的实例,函数(本身是对象)还是内置对象,所有调用(优化的特殊情况除外)都会到达函数PyObject_Call
。该C函数从对象的ob_type
结构的PyObject
字段获取对象的类型,然后从类型(另一个PyObject
结构)获取{ {1}}字段,它是一个函数指针。如果tp_call
不是tp_call
,则会通过调用,其中args和kwargs结构也会传递给NULL
。
当一个类定义PyObject_Call
方法时,它会相应地设置__call__
字段。
这是一篇详细解释所有这些内容的文章:Python internals: How callables work。它甚至列出并解释了整个tp_call
函数,它并不是很大。如果你想在其原生栖息地中看到该功能,它会在CPython回购中的Objects/abstract.c中。
这个stackoverflow Q& A:What is a "callable" in Python?也是相关的。
答案 1 :(得分:1)
没有实际的无限循环,因为__call__
方法实际上并未针对所有这些情况调用("称为#34;)。只有在提供__call__
方法的对象上有类似函数的调用时,才会直接调用它。
普通类实例化Cls(...)
和常规功能调用f()
是直接处理的已知案例。通常没有__call__()
的实际调用,因此即使在具有深度继承,元类等的复杂情况下,也可能发生有限数量的__call__
方法调用。
因为关于概念无限循环的短路是否真的发生存在争议,让我们看一下反汇编的字节码。请考虑以下代码:
def f(x):
return x + 1
class Adder(object):
def something(self, x):
return x + 19
def __call__(self, x):
return x + 1
def lotsacalls(y):
u = f(1)
a = Adder()
z = u + a.something(y)
return a(z * 10)
对不起,它有点复杂,因为我想展示几个短路实例 - 即正常def
函数,__init__
调用,普通方法和{{1}特殊方法。现在:
所以,如果Python确实是真正的,那么这里有很多次#34;走在树上"在概念__call__
调用中,它将引用__call__
(以及可能的Function
类,并调用它们的Method
方法。它没有。它在所有情况下都使用简单的字节码__call__
,使概念树向下走线短路。 逻辑上你可以想象有一个类CALL_FUNCTION
有一个Function
方法,当一个函数(即__call__
的一个实例被调用时类)被称为。但它并没有真正发挥作用。编译器,字节码解释器和C语言基础的其他部分不实际走元类树。他们像疯了一样短路。
答案 2 :(得分:0)
我没有查看任何文档,但是从我的测试中看来__call__
并不总是被调用:
def func1(*args, **kargs):
print "func1 called", args, kargs
def func2(*args, **kargs):
print "func2 called", args, kargs
func1.__call__ = func2
func1() # here is still called func1
class Cls:
def __init__(*args, **kargs):
print "init called", args, kargs
def __call__(*args, **kargs):
print "object called", args, kargs
obj = Cls() # here is actually called __init__
obj() # here is called __call__
打印
func1 called () {}
init called (<__main__.Cls instance at 0x0000000002A5ED88>,) {}
object called (<__main__.Cls instance at 0x0000000002A5ED88>,) {}