动态更新的实例类方法在被另一个类方法调用时抛出错误

时间:2011-12-17 22:29:29

标签: python lambda

我认为我的例子会让这更容易理解:

class x():
    def a(self):
        return "hello"
    def b(self):
        return self.a() + " world"

test = x()
print test.b()     # prints "hello world" as expected

test.a = lambda(self): "hola"
print test.b()     # throws error:
                   # Traceback (most recent call last):
                   #   File "<stdin>", line 1, in <module>
                   #   File "<stdin>", line 5, in b
                   # TypeError: <lambda>() takes exactly 1 argument (0 given)

尝试将x()。a更新到另一个函数,但是当x()。b调用它时,它似乎不会将self作为第一个参数传递。

我期待得到“hola world”。

2 个答案:

答案 0 :(得分:1)

如果你这样做,你可以看到问题

print type(test.a)  # <type 'function'>
print type(test.b)  # <type 'instancemethod'>

如果您确实只想在a上修补test(而不是x的所有实例),您可以执行以下操作:

import types
test.a = types.MethodType((lambda self: "hola"), test, x)

创建instancemethod类型的对象。

答案 1 :(得分:0)

保持笔直的功能和方法可能很棘手。一个好的经验法则是,如果你需要它作为一个方法,将它存储在类中。

你什么时候需要它才是一种方法?当代码访问实例或类的部分时。

在您的简单示例中,替换代码不访问实例,因此您可以在实例上保留一个函数,如下所示:

test.a = lambda: "hola"

这是一个访问实例的示例,代码存储在类中(这是您通常需要的):

x.c = lambda self: self.b().upper()

或存储在实例中:

# using MethodType
import types
test.c = types.MethodType((lambda self: self.b().upper()), test)

# using partial
import functools
test.c = functools.partial((lambda self: self.b().upper()), test)

# just using the instance name, as Ryan did
test.c = lambda: test.some_attribute

虽然最后一种方法大部分时间都可以使用,但确实存在一个缺陷:

oops = test
del oops
oops.c()

Traceback (most recent call last):
  File "test.py", line 42, in <module>
    oops.c()
  File "test.py", line 38, in <lambda>
    test.c = lambda: test.some_attribute
NameError: global name 'test' is not defined

要记住一些事情。