2010-07-07 29 views
6

也许我得到这个完全错误,但我遇到了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填充的类属性,并且在该阶段自引用类显然是不可能的。

+0

仅供参考,它适用于Python 3,但不适用于Python 2. – kennytm 2010-07-07 17:22:43

+0

@KennyTM,它适用于Python 3。 Python 3摆脱了绑定方法,只是返回函数本身。虽然这是一个很好的设计决定,但从概念上讲,最好用它来制造假静态方法。 – 2010-07-07 17:38:16

回答

2

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

class MyClass: 

    def LAMBDA(): 
    return MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

你,那么,显然这样称呼它MyClass.LAMBDA()。但看,LAMBDA是一种实例方法。而你在没有实际实例的情况下调用它。

你究竟想要做什么?

我认为,如果你给一个lambda结构的名字,你可能会声明它是'正常'的方式 - def。根据我的经验,当使用lambas实际上有助于代码质量时,只有少数几个孤立的情况。

+0

如果像那样定义,LAMBDA是一个*类成员*。不要让'lambda'让你分心。考虑'LAMBDA = 4'。 – kennytm 2010-07-07 17:27:01

+0

唉,缺乏'return'是一个真正的耻辱 – shylent 2010-07-07 17:30:49

+2

@KennyTM,“类成员”不是Python的术语,所以它似乎是一个奇怪的平台,选择nitpick。当shylent说这是一种方法时,他的意思就像我们经常这样做:他谈论的是语义上的事情,而不是名称。 – 2010-07-07 17:36:06

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大小写规则。)

0

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

但是从给定的代码,所有的LAMBDA将尽时,它被称为是自称MyClass.ClassMethod(),这意味着该方法做填充是ClassMethod(这是当然的,假设的ClassMethod身体不实际你已经显示出唯一的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'] 
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表单的。)所以“可调用”是用户递交的直拉姆达,必须用self.value()klass.value()调用,但value是未绑定函数(lambda或其他)。