lambda 调用 @classmethod 失败

6 投票
4 回答
1720 浏览
提问于 2025-04-16 00:57

也许我理解错了,但我在使用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 个回答

1

这里还有一个直接的解决办法。虽然这可能不是最优雅的方式,但我觉得这正是你想知道的。我自己也遇到过类似的情况。你可以用 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 还是其他的)。

2

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。另外,ClassMethodLAMBDA的命名方式也不符合普通的Python命名规则。)

2

你得明白,你的代码实际上和下面这段是一样的:

class MyClass:

  def LAMBDA():
    return MyClass.ClassMethod()

  @classmethod
  def ClassMethod(cls):
    pass

然后,你似乎是用 MyClass.LAMBDA() 这样的方式来调用它。但注意,LAMBDA 是一个实例方法,而你却没有一个实际的实例在这里。

你到底想做什么呢?

我觉得,如果你是想给一个 lambda 表达式起个名字,那不如直接用 def 来定义它。根据我的经验,只有在少数情况下,使用 lambda 才真的能提高代码的质量。

撰写回答