>>> def f():
... def __call__(x):
... return x
...
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
>>> f.__call__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
问题是在定义f
及其私有子功能__call__
时 - 以及在尝试调用该函数之后(认为它会调用__call__
覆盖)它会抛出一个错误,指出函数没有接受任何参数,但是传递了一个。
而且(很明显 - 后见之明)试图调用__call__
方法,它会给出完全相同的错误。
关于这一点,我很困惑,因为我认为首先会定义f
,然后它会创建基本的私有方法(如__str__
,__name__
,{ {1}}等等,然后显式__repr__
方法的定义将取代隐式生成的__call__
方法。
有人可以解释函数定义的顺序是什么,以及首先和最后声明的内容,或解释如何设法覆盖隐藏的__call__
(如果可能的话,最好不使用类来掩盖一个功能)。
答案 0 :(得分:4)
函数中的命名空间不会生成属性。 __call__
是f()
内的局部变量,仅此而已。
def <identifier>(...):
绑定当前命名空间中的名称identifier
,并在函数中绑定一个本地名称,就像some_name = ...
一样。
最多可以返回该对象:
>>> def f():
... def __call__(x):
... return x
... return __call__ # return the local variable
...
>>> f()
<function f.<locals>.__call__ at 0x10e946400>
>>> f()(1)
1
如果函数中的所有局部变量都成为属性,甚至在您实际执行该函数之前,这将是非常令人惊讶的!
但是,即使您为函数对象提供了__call__
属性,仍然不会使用。您只能使用类创建一个__call__
方法的对象:
class Foo:
def __call__(self, x):
return x
foo = Foo()
foo() # returns 1
那是因为__call__
是一个特殊方法,因此受Special method lookup rules的约束,后者规定Python会在类型上寻找方法对象,而不是对象本身。
当Python评估foo(...)
时,如果foo
不是函数对象,Python将执行type(foo).__call__(foo, ...)
。 Python这样做是为了确保在使用Foo.__call__
创建实例时不使用Foo()
方法;类也是可调用的,但定义Foo.__call__
不应该与之冲突。
答案 1 :(得分:0)
您要求避免的是__call__
的用途。它允许带有该方法的对象伪装成一个函数。当您定义一个函数时,您不会创建一个具有属性的对象 - 根本没有定义名为__call__
的方法(至少您自己定义了...)表示函数f
的对象。
然而,事实证明你已经有一个处理你的电话的功能,即f
。如果需要,您也可以使用装饰器来包装该功能,或者如您所建议的那样,创建一个类并改为实例化对象。