2

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

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

4

2 回答 2

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。

于 2013-12-25T06:59:13.060 回答
2

一个函数——无论是用lambda还是定义的def——都不是方法。

你不能只是改变它的类型;方法比函数包含更多信息——它绑定到一个对象。这就是 Python 知道为第一个 ( self) 参数传递什么的方式。

在您的情况下,您正在寻找一个未绑定的方法,它没有绑定到一个对象——但它仍然绑定到一个

在正常情况下(当您def在定义中创建一个方法class,然后创建该类的一个实例,然后在其上调用一个方法),这会为您自动发生。(有关详细信息,请参阅方法的工作原理。)但是当您自己完成所有操作时,您需要自己创建绑定方法。

与 Python 中的任何其他类型一样,您可以通过将类型调用为构造函数来完成此操作。问题是“绑定方法”不能作为内置类型访问。这意味着您必须转到该types模块,该模块“为标准 Python 解释器使用的某些对象类型定义名称”。像这样:

bound = types.MethodType(func, my_obj, type(my_obj))

unbound = types.UnboundMethodType(func, None, my_type)

但请注意,通常没有充分的理由这样做——您可以轻松地将对象塞入闭包中。这些可调用对象都会做同样的事情:

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)    

最后的两个想法:

如果您了解描述符,那么使@property工作的魔法和使绑定方法工作的魔法将相互干扰。我不知道 Enthough 特性是否如此,但它可能。所以,你的问题的答案很可能是“你不能那样做”。相反,您必须创建一个Function特征,然后创建一个显式调用该特征的包装器方法。

如果您使用 Python 3.x 而不是 2.x,那么未绑定的方法就会消失(类只使用普通的旧函数),因此您遇到的许多复杂性永远不会出现。

于 2013-12-24T21:07:28.030 回答