在python中使对象可调用的问题

时间:2009-11-10 06:06:35

标签: 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 个答案:

答案 0 :(得分:18)

在正在操作的对象的类型(例如,类)上查找特殊方法,而不是在特定实例上查找。考虑一下:否则,如果一个类定义__call__,例如,当调用类时__call__应该被调用...这真是一场灾难!但幸运的是,特殊的方法是在类的类型,AKA元类上查找,而且一切都很好(“遗留类”在这方面有非常不规则的行为,这就是为什么我们的新风格更好 - 这是Python 3)中唯一剩下的。

因此,如果您需要“按实例覆盖”特殊方法,则必须确保实例具有自己的唯一类。这很容易:

class a(object):
    def __init__(self):
        self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
        self.__class__.__call__ = lambda x:x

你在那儿。当然,在这种情况下这将是愚蠢的,因为每个实例最终只有相同的“所谓的每个实例”(!)__call__,但如果你真的需要覆盖一个个人实例。

答案 1 :(得分:14)

需要在类上定义

__call__,而不是实例

class a(object):
    def __init__(self):
        pass
    __call__ = lambda x:x

但大多数人可能会发现以通常的方式定义方法更具可读性

class a(object):
    def __init__(self):
        pass
    def __call__(self):
        return self

如果你需要为每个实例提供不同的行为,你可以这样做

class a(object):
    def __init__(self):
        self.myfunc = lambda x:x

    def __call__(self):
        return self.myfunc(self)

答案 2 :(得分:1)

这个怎么样? 定义基类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