简体   繁体   English

Python如何分辨“这被称为函数”?

[英]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 ----- >% ----- -----%<-----编辑----->%-----

Conclusions and other experiments after one answer and one comment 一个答案和一个评论后的结论和其他实验

Update #1 更新#1

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. 如果我正确理解,则元类不仅与类无关,而且与类实例也无关。

Update #2 更新#2

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.

相关问题 如何判断是否已在Python中调用过函数? - How do I tell whether a function has been called in Python? 如何判断何时调用另一个类中的函数 - How to tell when a function in another class has been called 如何判断是否正在从 jupyter notebook 调用函数? - How to tell whether a function is being called from a jupyter notebook or not? 在Python中,如何判断是否被异常处理代码调用? - In Python, how to tell if being called by exception handling code? 如何判断脚本是独立运行还是在python中称为子进程 - how to tell if a script is running independently or called as subprocess in python Python:如何告诉 for 循环从函数继续? - Python: How to tell the for loop to continue from a function? 我如何告诉 PyCharm 用户定义的 function 字典中的 python 类型是可以的? - How do I tell PyCharm user defined type of python dict in a function is okay? Python 3 - 你如何告诉 pipenv 使用 python 3 而不是 python 2? - Python 3 - How do you tell pipenv to use python 3 and not python 2? python函数如何调用而不等待它完成处理,而该函数必须被调用一次。 因此,线程必须停止 - How a python function called and do not wait it finish processing meanwhile that function must be called once. So, thread must be stop 如何获得在另一个函数中调用的函数以返回值? 蟒蛇 - How do I get a function that is called within another function to return a value? PYTHON
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM