lambda 调用 @classmethod 失败
也许我理解错了,但我在使用lambda调用@classmethod时遇到了一些奇怪的问题。
我有一个这样的类:
class MyClass:
LAMBDA = lambda: MyClass.ClassMethod()
@classmethod
def ClassMethod(cls):
pass
但是每当调用LAMBDA时,这个就会失败:
TypeError: unbound method <lambda>() must be called with MyClass instance as first argument (got nothing instead)
我真的不明白为什么会这样。我已经花了一些时间试图让它正常工作。我需要一些类属性通过这个lambda来填充,但在那个阶段显然无法自我引用这个类。
4 个回答
这里还有一个直接的解决办法。虽然这可能不是最优雅的方式,但我觉得这正是你想知道的。我自己也遇到过类似的情况。你可以用 staticmethod()
来故意解除绑定。
这是错误的版本:
def bar(): return 0
class foo(object):
x = lambda:bar()
@classmethod
def grok(klass):
return klass.x()
foo().grok()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "<console>", line 4, in grok
TypeError: unbound method <lambda>() must be called with foo instance as first argument (got nothing instead)
这是稍微调整过的版本:
def bar(): return 0
class foo(object):
x = staticmethod(lambda:bar())
@classmethod
def grok(klass):
return klass.x()
foo().grok()
0
注意,上面提到的情况也适用于:
x = bar
其实,我只是把这个 lambda 加进来,是为了直接回应问题。以上所有建议都有效,这只是尽量少改动代码的一种直接方式。
至于为什么会想让像上面那样的东西与 lambda 一起工作呢?在我的情况下,我在制作一个工厂类,这个类有事件处理器,偶尔会使用类级别的数据来获取信息,而这些信息有些是值或者可调用的性质。(这是为了一个 Django 表单。)所以“可调用的”就是用户直接提供的一个 lambda,它必须用 self.value()
或 klass.value()
来调用,但 value
是一个未绑定的函数(无论是 lambda 还是其他的)。
LAMBDA
在这里其实就是一个普通的方法。当你在类里查找它时,你会得到一个未绑定的方法,这有点儿奇怪,因为它会要求你的函数的第一个参数必须是这个类的一个实例,尽管self
还没有被传入。
再说一遍,LAMBDA = lambda: MyClass.ClassMethod()
和def LAMBDA(): return MyClass.ClassMethod()
其实没有什么区别。在后者的情况下,更清楚地表明你有一个不太完整的方法定义。lambda函数和def函数实际上是同一种类型的对象,Python在查找时会根据相同的规则将它们转化为方法。
我猜你可能想要的代码是
class MyClass(object):
@classmethod
def ClassMethod(cls):
pass
MyClass.LAMBDA = MyClass.ClassMethod
或者
class MyClass(object):
@classmethod
def ClassMethod(cls):
pass
@classmethod
def LAMBDA(cls):
return cls.ClassMethod()
(注意最后一个可以像你最开始那样用lambda写,但其实没必要。我个人在代码中从来不会用= lambda
。另外,ClassMethod
和LAMBDA
的命名方式也不符合普通的Python命名规则。)
你得明白,你的代码实际上和下面这段是一样的:
class MyClass:
def LAMBDA():
return MyClass.ClassMethod()
@classmethod
def ClassMethod(cls):
pass
然后,你似乎是用 MyClass.LAMBDA()
这样的方式来调用它。但注意,LAMBDA 是一个实例方法,而你却没有一个实际的实例在这里。
你到底想做什么呢?
我觉得,如果你是想给一个 lambda 表达式起个名字,那不如直接用 def
来定义它。根据我的经验,只有在少数情况下,使用 lambda 才真的能提高代码的质量。