为什么不向实例工作中动态添加`__call__`方法? [英] Why won't dynamically adding a `__call__` method to an instance work?

查看:83
本文介绍了为什么不向实例工作中动态添加`__call__`方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Python 2和Python 3中,代码:

In both Python 2 and Python 3 the code:

class Foo(object):
    pass

f = Foo()
f.__call__ = lambda *args : args

f(1, 2, 3)

返回错误Foo object is not callable.为什么会发生这种情况?

returns as error Foo object is not callable. Why does that happen?

PS:使用老式类,它可以按预期工作.

PS: With old-style classes it works as expected.

PPS:此行为是有意的(请参阅接受的答案).作为一种变通办法,可以在类级别定义一个__call__,该__call__仅转发给另一个成员,并将该普通"成员设置为按实例__call__的实现.

PPS: This behavior is intended (see accepted answer). As a work-around it's possible to define a __call__ at class level that just forwards to another member and set this "normal" member to a per-instance __call__ implementation.

推荐答案

双下划线方法始终在类中查找,而不是在实例中查找.请参见 特殊方法查找对于新型类 :

Double-underscore methods are always looked up on the class, never the instance. See Special method lookup for new-style classes:

对于新型类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作.

For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.

这是因为类型可能需要支持相同的操作(在这种情况下,将在元类型上查找特殊方法).

That's because the type might need to support the same operation (in which case the special method is looked up on the metatype).

例如,类是可调用的(这就是您生成实例的方式),但是如果Python在实际对象上查找__call__方法 ,那么您将永远无法在实现了__call__(针对其实例). ClassObject()将变为ClassObject.__call__(),这将失败,因为self参数未传递到未绑定的方法中.因此,改为使用type(ClassObject).__call__(ClassObject),并且调用instance()会转换为type(instance).__call__(instance).

For example, classes are callable (that's how you produce an instance), but if Python looked up the __call__ method on the actual object, then you could never do so on classes that implement __call__ for their instances. ClassObject() would become ClassObject.__call__() which would fail because the self parameter is not passed in to the unbound method. So instead type(ClassObject).__call__(ClassObject) is used, and calling instance() translates to type(instance).__call__(instance).

要变通解决此问题,您可以向该类中添加一个__call__方法,该方法检查该类上的__call__属性,如果存在,则对其进行调用.

To work around this, you could add a __call__ method to the class which checks for a __call__ attribute on the class, and if there, calls it.

这篇关于为什么不向实例工作中动态添加`__call__`方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆