在Python中使对象可调用的问题
我写了这样的代码
>>> class a(object):
def __init__(self):
self.__call__ = lambda x:x
>>> b = a()
我原本以为类 a
的对象应该是可以被调用的,但显然它不是,我搞不懂为什么。
>>> b()
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
b()
TypeError: 'a' object is not callable
>>> callable(b)
False
>>> hasattr(b,'__call__')
True
3 个回答
2
这个怎么样呢?
首先,定义一个基础类叫做 AllowDynamicCall:
class AllowDynamicCall(object):
def __call__(self, *args, **kwargs):
return self._callfunc(self, *args, **kwargs)
然后,创建一个继承自 AllowDynamicCall 的子类:
class Example(AllowDynamicCall):
def __init__(self):
self._callfunc = lambda s: s
20
__call__
这个方法需要在类里面定义,而不是在实例里面。
class a(object):
def __init__(self):
pass
def __call__(self):
return self
(这里用 def
是因为 PEP8 不建议使用命名的 lambda 函数。)
如果你想让每个实例有不同的行为,可以这样做:
class a(object):
def __init__(self):
self.myfunc = lambda x:x
def __call__(self):
return self.myfunc(self)
21
特殊方法是根据对象的类型(比如说类)来查找的,而不是根据具体的实例来查找。想想看,如果一个类定义了 __call__
方法,那么当这个类被调用时,__call__
方法应该被执行……那可真是个大麻烦!但幸运的是,特殊方法是根据类的类型,也就是元类来查找的,这样一切就正常了(“旧式类”在这方面表现得非常不规律,所以我们现在都用新式类,而在Python 3中只有新式类可用)。
所以,如果你需要对特殊方法进行“每个实例单独覆盖”,你必须确保每个实例都有自己独特的类。这其实很简单:
class a(object):
def __init__(self):
self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
self.__class__.__call__ = lambda x:x
这样就可以了。当然,在这个情况下这样做有点傻,因为每个实例最终都只有一个相同的“所谓每个实例的” __call__
方法,但如果你真的需要针对每个单独的实例进行覆盖,这样做就很有用了。