lambda调用@classmethod失败

时间:2010-07-07 17:18:21

标签: python

也许我完全错了但是我遇到了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 个答案:

答案 0 :(得分:2)

您必须明白,您的代码完全等同于

class MyClass:

  def LAMBDA():
    return MyClass.ClassMethod()

  @classmethod
  def ClassMethod(cls):
    pass

然后,你显然称它为MyClass.LAMBDA()。但是看,LAMBDA是一种实例方法。并且你在没有实际实例的情况下调用它。

你究竟想做什么?

我估计,如果你给一个lambda结构命名,你也可以将它称为“正常”方式 - def。根据我的经验,当使用lambas实际上有助于代码质量时,只有少数孤立的案例。

答案 1 :(得分: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。请注意ClassMethod并且LAMBDA不遵循正常的Python大小写样式规则。)

答案 2 :(得分: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形式。)所以“callable”是一个由用户提交的直接lambda,必须使用self.value()klass.value()调用,但value是未绑定的功能(lambda或其他)。

答案 3 :(得分:0)

  

我需要一些由该lambda填充的类属性,并且在该阶段显然不可能自引用该类。

但是从您给定的代码中,所有LAMBDA在调用时都会执行调用MyClass.ClassMethod(),这意味着执行填充的方法是ClassMethod(这当然是假设正文ClassMethod的{​​{1}}实际上并不是你所展示的唯一pass,因为如果它正在做所有这一切都是徒劳的练习。除非您的代码的某些方面阻止您在将其用于任何内容之前引用该类,否则为什么不能在类定义之后调用MyClass.ClassMethod()

如果你试图在定义中修改类的属性(也就是说,在MyClass的定义中调用LAMBDA,在任何方法/函数/之外调用),你可能想看看这个部分有关metaclasses的文档。

另外,如果你想为一个类赋予属性,你甚至不需要在类本身中这样做。

>>> class cls(object):  # or just "class cls:"
...     pass
...
>>> cls.value = 10
>>> cls.name = 'class'
>>> cls.value
10
>>> cls.name
'class'
>>> dir(cls)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'name', 'value']