【发布时间】:2014-09-10 17:22:20
【问题描述】:
通过定义__call__,一个可调用对象应该是这样的。一个类应该是一个对象……或者至少有一些例外。这个例外是我没有正式澄清的,因此这里发布了这个问题。
让A 成为一个简单的类:
class A(object):
def call(*args):
return "In `call`"
def __call__(*args):
return "In `__call__`"
第一个函数特意命名为“call”,目的是为了和其他函数进行比较。
让我们实例化它并忘记它所暗示的表达式:
a = A() # Think of it as `a = magic` and forget about `A()`
现在有什么价值:
print(A.call())
print(a.call())
print(A())
print(a())
结果:
>>> In `call`
>>> In `call`
>>> <__main__.A object at 0xNNNNNNNN>
>>> In `__call__`
输出(第三条语句未运行__call__)并不令人意外,但当我想到每个地方都说“Python 类是对象”时......
这个,更明确,但是运行__call__
print(A.__call__())
print(a.__call__())
>>> “In `__call__`”
>>> “In `__call__`”
所有这些只是为了表明A() 最终看起来可能很奇怪。
Python 规则中也有例外,但the documentation about “object.call” 并没有对__call__ 多说……仅此而已:
3.3.5。模拟可调用对象
object.__call__(self[, args...])当实例作为函数“调用”时调用; […]
但是 Python 如何判断“它被称为函数”以及是否遵守 object.__call__ 规则?
这可能与类型有关,但即使是类型也有 object 作为其基类。
我在哪里可以了解更多(正式)相关信息?
顺便问一下,这里Python2和Python3有什么区别吗?
----- %% -----
一答一评论后的结论及其他实验
更新 #1
在@Veedrac 的回答和@chepner 的评论之后,我来到了另一个测试,它完成了两者的 cmets:
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())
结果是:
>>> In `M.__call__`
所以看起来这是驱动“调用”操作的元类。如果我理解正确,元类不仅与类有关,还与类实例有关。
更新 #2
另一个相关的测试表明,重要的不是对象的属性,而是对象类型的属性:
class A(object):
def __call__(*args):
return "In `A.__call__`"
def call2(*args):
return "In `call2`"
a = A()
print(a())
正如预期的那样,它会打印:
>>> In `A.__call__`
现在这个:
a.__call__ = call2
print(a())
打印出来:
>>> In `A.__call__`
分配属性之前的相同a。它不打印In call2,它仍然是In A.__call__。重要的是要注意并解释为什么这是被调用的元类的__call__(请记住,元类是类对象的类型)。 __call__ 用来作为函数调用,不是来自对象,而是来自它的类型。
【问题讨论】:
-
A.__call__()不按您演示的方式工作。它不会打印In __call__。 -
这至少是它对 Python 3.4 所做的事情(您使用的是较旧的 Python 版本吗?)
-
Instances of
A是可调用的;根据对象的类型查找特殊方法;例如,您不能将__call__设为实例的属性。 -
只是因为您使用
*args进行签名。打印出args是什么,你会看到那里的不同。您正在那里访问 函数对象。 -
你知道吗?函数是可调用的。当你直接打电话给他们时,你给他们起什么名字并不重要。
标签: python