[英]How do Python tell “this is called as a function”?
A callable object is supposed to be so by defining __call__
. 应该通过定义
__call__
来实现可调用对象。 A class is supposed to be an object… or at least with some exceptions. 一个类应该是一个对象……或至少有一些例外。 This exception is what I'm failing to formally clarify, thus this question posted here.
这个例外是我无法正式澄清的,因此此问题在此处发布。
Let A
be a simple class: 令
A
为一个简单的类:
class A(object):
def call(*args):
return "In `call`"
def __call__(*args):
return "In `__call__`"
The first function is purposely named “call”, to make clear the purpose is the comparison with the other. 第一个功能特意命名为“调用”,以明确目的是与另一个功能进行比较。
Let's instantiate it and forget about the expression it implies: 让我们实例化它,而忽略它所暗示的表达式:
a = A() # Think of it as `a = magic` and forget about `A()`
Now what's worth: 现在值得:
print(A.call())
print(a.call())
print(A())
print(a())
Result in: 导致:
>>> In `call`
>>> In `call`
>>> <__main__.A object at 0xNNNNNNNN>
>>> In `__call__`
The output (third statement not running __call__
) does not come as a surprise, but when I think every where it is said “Python class are objects”… 输出(第三条未运行
__call__
语句)不足为奇,但是当我认为每个地方都说“ Python类是对象”时……
This, more explicit, however run __call__
这个更明确,但是运行
__call__
print(A.__call__())
print(a.__call__())
>>> “In `__call__`”
>>> “In `__call__`”
All of this is just to show how finally A()
may looks strange. 所有这些只是为了说明
A()
最终看起来如何奇怪。
There are exception in Python rules, but the documentation about “object. Python规则中有例外,但是有关“对象。 call ” does not say a lot about
__call__
… not more than that: 呼叫 ”并没有说太多有关
__call__
…… __call__
:
3.3.5.
3.3.5。 Emulating callable objects
模拟可调用对象
object.__call__(self[, args...])
Called when the instance is “called” as a function;
当实例被“调用”为函数时调用; […]
[…]
But how do Python tell “it's called as a function” and honour or not the object.__call__
rule? 但是,Python如何告诉“它被称为一个函数”,而不尊重
object.__call__
规则?
This could be a matter of type, but even type has object
as its base class. 这可能是类型问题,但即使类型也将
object
作为其基类。
Where can I learn more (and formally) about it? 在哪里可以了解更多(正式)信息?
By the way, is there any difference here between Python 2 and Python 3? 顺便说一句,Python 2和Python 3之间有什么区别吗?
----- %< ----- edit ----- >% ----- -----%<-----编辑----->%-----
After @Veedrac's answer and @chepner's comment, I came to this other test, which complete the comments from both: 在@Veedrac的回答和@chepner的评论之后,我参加了另一个测试,该测试完成了两个评论:
class M(type):
def __call__(*args):
return "In `M.__call__`"
class A(object, metaclass=M):
def call(*args):
return "In `call`"
def __call__(*args):
return "In `A.__call__`"
print(A())
The result is: 结果是:
>>> In `M.__call__`
So it seems that's the meta‑class which drives the “call” operations. 因此,似乎是元类驱动了“调用”操作。 If I understand correctly, the meta‑class does not matter only with class, but also with classes instances.
如果我正确理解,则元类不仅与类无关,而且与类实例也无关。
Another relevant test, which shows this is not an attribute of the object which matters, but an attribute of the type of the object: 另一个相关的测试表明这不是重要的对象属性,而是对象类型的属性:
class A(object):
def __call__(*args):
return "In `A.__call__`"
def call2(*args):
return "In `call2`"
a = A()
print(a())
As expected, it prints: 如预期的那样,它将打印:
>>> In `A.__call__`
Now this: 现在这个:
a.__call__ = call2
print(a())
It prints: 它打印:
>>> In `A.__call__`
The same a before the attribute was assigned. 分配属性之前的相同“ a”。 It does not print
In call2
, it's still In A.__call__
. 它不会
In call2
打印,仍在In A.__call__
。 That's important to note and also explain why that's the __call__
of the meta‑class which was invoked (keep in mind the meta‑class is the type of the class object). 注意这一点很重要,并说明为什么这就是被
__call__
的元类的__call__
(请注意,元类是类对象的类型)。 The __call__
used to call as function, is not from the object, it's from its type. 用作函数调用的
__call__
不是来自对象,而是来自其类型。
x(*args, **kwargs)
is the same as type(x).__call__(x, *args, **kwargs)
. x(*args, **kwargs)
与type(x).__call__(x, *args, **kwargs)
相同type(x).__call__(x, *args, **kwargs)
。
So you have 所以你有了
>>> type(A).__call__(A)
<__main__.A object at 0x7f4d88245b50>
and it all makes sense. 这一切都说得通。
chepner points out in the comments that type(A) == type
. chepner在注释中指出
type(A) == type
。 This is kind-of wierd, because type(A)(A)
just gives type
again! 这有点奇怪,因为
type(A)(A)
再次给出了type
! But remember that we're instead using type(A).__call__(A)
which is not the same . 但请记住,我们不是使用
type(A).__call__(A)
这是不一样的 。
So this resolves to type.__call__(A)
. 所以这解析为
type.__call__(A)
。 This is the constructor function for classes, which builds the data-structures and does all the construction magic. 这是类的构造函数,它构造数据结构并完成所有构造魔术。
The same is true of most dunder (double underscore) methods, such as __eq__
. 大多数dunder(双下划线)方法(例如
__eq__
)也是如此。 This is partially an optimisation in those cases. 在某些情况下,这是部分优化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.