我想创建一个基于函数的实例方法,作为参数 实例初始化,如下:
from traits.api import *
class C(HasTraits):
f = Function
c = C(f=lambda self: self)
但是,如果我跑
c.f()
它说(不以任何方式令人惊讶)
TypeError: <lambda>() takes exactly 1 argument (0 given)
将f从Function更改为Method无效,因为它不接受该功能 参数(需要instancemethod)。
所以我的问题是,在使用Traits时,如何将自定义函数作为实例方法(使用self参数作为普通实例方法)?
答案 0 :(得分:2)
使用lambda
或def
定义的函数不是方法。
你不能只改变它的类型;一个方法中包含的信息多于一个函数 - 它绑定到一个对象。这就是Python如何知道第一个(self
)参数传递的内容。
在您的情况下,您正在寻找未绑定方法,它未绑定到对象 - 但它仍然绑定到类< / em>的
在正常情况下(当你在def
定义中class
一个方法,然后创建一个类的实例,然后在其上调用一个方法),这会自动发生。 (有关详细信息,请参阅How methods work。)但是当您自己完成所有操作时,您需要自己创建绑定方法。
与Python中的任何其他类型一样,您可以通过将类型作为构造函数来调用。问题是“绑定方法”不能作为内置类型访问。这意味着您必须转到types
模块,该模块“定义标准Python解释器使用的某些对象类型的名称”。像这样:
bound = types.MethodType(func, my_obj, type(my_obj))
unbound = types.UnboundMethodType(func, None, my_type)
但请注意,通常没有充分的理由这样做 - 你可以轻松地将对象塞进闭包中。这些callables都会做同样的事情:
func = lambda self: self
bound = types.MethodType(func, my_obj, type(my_obj))
func2 = lambda: my_obj
func3 = lambda self: self
unbound = types.UnboundMethodType(func, None, my_type)
func3a = lambda: unbound(my_obj)
最后两个想法:
如果您了解descriptors,那么使@property
起作用的魔力以及使绑定方法起作用的魔力将相互干扰。我不知道这是否与Enthough特征一致,但它可能。所以,你的问题的答案可能会变成“你不能那样做”。相反,您必须创建一个Function
特征,然后创建一个显式调用该特征的包装器方法。
如果使用Python 3.x而不是2.x,则未绑定的方法会消失(类只使用普通的旧函数),因此您所遇到的很多复杂性永远不会出现。
答案 1 :(得分:2)
定义新的Trait类型MyMethod,如下所示:
import types
class MyMethod(TraitType):
def validate(self, object, name, value):
if isinstance(value, types.MethodType):
return value
if isinstance(value, types.FunctionType):
return types.MethodType(value, object, object.__class__)
self.error(object, name, value)
并在前面的代码中使用它代替Function或Method,函数将自动转换为instancemethods。