我想做的是这样的:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
# programatically set the "default" operation
fer=Foo()
fer.__call__=fer.f
# a different instance does something else as its
# default operation
ger=Foo()
ger.__call__=ger.g
fer() # invoke different functions on different
ger() # objects depending on how they were set up.
Run Code Online (Sandbox Code Playgroud)
但从 2.7(我目前正在使用)开始,我无法执行此操作,尝试fer()
引发异常。
实际上,有没有办法设置每个实例的__call__方法?
不幸的是,普通的东西types.MethodType在这里不起作用,因为__call__它是一种特殊的方法。
从数据模型来看:
仅当类具有
__call__()方法时,类实例才可调用;x(arguments) 是 的简写x.__call__(arguments)。
这对于实际调用的内容有点含糊,但很明显您的类需要有一个__call__方法。
你需要创建某种黑客:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def __call__(self):
return self.__call__()
f = Foo()
f.__call__ = f.f
f()
g = Foo()
g.__call__ = g.g
g()
Run Code Online (Sandbox Code Playgroud)
__call__不过要小心,如果在尝试调用实例之前没有在实例上设置 a ,则会导致无限递归。
请注意,我实际上并不建议调用您重新绑定的 magic 属性__call__。这里的重点是演示 python 翻译f()为: f.__class__.__call__(f),因此您无法在每个实例的基础上更改它。无论你做什么,类__call__都会被调用——你只需要做一些事情来改变类的__call__每个实例的行为,这很容易实现。
您可以使用 setter 类型的东西在您的类上实际创建方法(而不是简单的函数)——当然,这可以转换为属性:
import types
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def set_func(self,f):
self.func = types.MethodType(f,self)
def __call__(self,*args,**kwargs):
self.func(*args,**kwargs)
f = Foo()
f.set_func(Foo.f)
f()
def another_func(self,*args):
print args
f.set_func(another_func)
f(1,2,3,"bar")
Run Code Online (Sandbox Code Playgroud)