使用函数作为Enthought Traits(Python)的实例方法

时间:2013-12-24 20:55:32

标签: python lambda traitsui

我想创建一个基于函数的实例方法,作为参数 实例初始化,如下:

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参数作为普通实例方法)?

2 个答案:

答案 0 :(得分:2)

使用lambdadef定义的函数不是方法。

你不能只改变它的类型;一个方法中包含的信息多于一个函数 - 它绑定到一个对象。这就是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。