2010-07-07 7 views
6

Vielleicht bekomme ich das völlig falsch, aber ich stieß auf einige seltsame Probleme mit Lambda Aufruf von @classmethod.Lambda Aufruf @classmethod schlägt fehl

Ich habe die folgende Klasse:

class MyClass: 
    LAMBDA = lambda: MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

Aber dies fehlschlägt, wenn LAMBDA mit aufgerufen:

TypeError: unbound method <lambda>() must be called with MyClass instance as first argument (got nothing instead) 

Ich verstehe nicht wirklich, warum das so ist. Ich habe schon einige Zeit damit verbracht, das zu schaffen. Ich brauche einige Klassenattribute, die von diesem Lambda bevölkert werden, und die Selbstreferenzierung der Klasse ist in diesem Stadium offensichtlich nicht möglich.

+0

FYI, Dies funktioniert auf Python 3, aber nicht auf Python 2. – kennytm

+0

@KennyTM, Es funktioniert auf Python 3 durch Zufall. Python 3 wurde die gebundene Methode los und gibt nur die Funktion selbst zurück. Obwohl dies eine gute Design-Entscheidung ist, ist es konzeptuell bestenfalls, es zu benutzen, um falsche statische Methoden zu erstellen. –

Antwort

2

Sie müssen verstehen, dass Ihr Code zu

class MyClass: 

    def LAMBDA(): 
    return MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

Sie dann genau das gleiche, es scheinbar wie MyClass.LAMBDA() nennen. Aber schau, LAMBDA ist eine Instanzmethode. Und Sie nennen es ohne eine tatsächliche Instanz an Ort und Stelle.

Was genau versuchen Sie zu tun?

Ich denke, wenn Sie einem Lambda-Konstrukt einen Namen geben, können Sie es genauso gut als "normal" deklarieren - def. Aus meiner Erfahrung gibt es nur vereinzelte Fälle, in denen Lambda tatsächlich zur Codequalität beiträgt.

+0

LAMBDA ist ein * Klassenmitglied *, wenn es so definiert ist. Lassen Sie sich nicht vom 'Lambda' ablenken. Betrachte 'LAMBDA = 4'. – kennytm

+0

bah, der Mangel an "Rückkehr" war eine echte Schande – shylent

+2

@KennyTM, "Klassenmitglied" ist nicht Python-Terminologie, so scheint es wie eine ungerade Plattform zu wählen, um auf nitpick auf. Wenn Shylent sagt, dass es eine Methode ist, meint er es so, wie wir es immer tun: Er redet über das Bedeutungshafte, nicht über den Namen. –

2

LAMBDA Hier ist nur eine normale Methode. Wenn Sie in der Klasse suchen, erhalten Sie eine ungebundene Methode, die eine Art dumme Sache ist, die Ihre Funktion übernimmt und auferlegt - obwohl self noch nicht übergeben wird - das erste Argument muss eine Instanz sein der Klasse in Frage.

Um zu wiederholen, ist nicht anders als def LAMBDA(): return MyClass.ClassMethod(). Im letzteren Fall ist es klarer, dass Sie eine Art defekter Methodendefinition haben. Eine Lambda-Funktion und eine Def-Funktion bilden die genau gleichen Arten von Objekten, und Python verwandelt sie in Methoden mit den gleichen Regeln während der Nachschlagezeit.

Ich vermute, der Code Sie vielleicht

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 
MyClass.LAMBDA = MyClass.ClassMethod 

ist oder

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 

    @classmethod 
    def LAMBDA(cls): 
     return cls.ClassMethod() 

(Hinweis: Um diesen letzten mit einem Lambda geschrieben werden kann, wie Sie ursprünglich taten, aber es gibt keinen Grund zu. I würde nie = lambda in irgendeinem meines Codes persönlich verwenden. Beachte auch, dass ClassMethod und LAMBDA nicht den normalen Python-Kapitalisierungsstil-Regeln folgen.)

0

Ich brauche einige Klassenattribute, die von diesem Lambda bevölkert werden, und die Selbstreferenzierung der Klasse ist in dieser Phase offensichtlich nicht möglich.

Aber von Ihrem bestimmten Code, werden alle LAMBDA tun, wenn es genannt wird, ist selbst MyClass.ClassMethod() nennen, was die Methode bedeutet, ist das Bestücken tun ClassMethod (dies ist natürlich unter der Annahme, dass der Körper von ClassMethod nicht wirklich ist diese Sohle pass hast du gezeigt, denn wenn es dann alles tut, ist das eine Übung in Vergeblichkeit).Es sei denn, es gibt einen Aspekt Ihres Codes, der Sie davon abhält, auf die Klasse zu verweisen, bevor Sie sie für irgendetwas verwenden. Warum können Sie nicht nach der Klassendefinition MyClass.ClassMethod() aufrufen?

Und wenn Sie versuchen, Attribute der Klasse innerhalb der Definition (dh Aufruf von LAMBDA innerhalb der Definition von MyClass, außerhalb von irgendwelchen Methoden/Funktionen/was auch immer) zu ändern, möchten Sie vielleicht einen Blick auf die Abschnitt der Dokumentation über metaclasses.

Wenn Sie einer Klasse Attribute zuweisen möchten, müssen Sie dies nicht einmal im Rumpf der Klasse selbst tun.

>>> 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

Es gibt eine andere direkte Lösung dafür. Vielleicht ist das nicht die sauberste Sache, aber ich denke, es ist das, worüber du dich wunderst. Ich bin selbst in eine ähnliche Situation geraten. Sie können es absichtlich mit staticmethod() lösen.

Hier ist die fehlerhafte Version:

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) 

Und die leicht angepasst Version:

def bar(): return 0 

class foo(object): 
    x = staticmethod(lambda:bar()) 
    @classmethod 
    def grok(klass): 
    return klass.x() 

foo().grok() 

0 

Beachten Sie, dass beide der oben genannten auch auftreten:

x = bar 

statt. Ich habe gerade das Lambda als direkte Antwort auf die Frage eingefügt. Alle oben genannten Vorschläge funktionieren auch, dies ist nur eine direkte Möglichkeit, den Code so wenig wie möglich zu ändern.

Warum würde man jemals so etwas wie das oben genannte mit Lambdas machen wollen? In meinem Fall erstellte ich eine Factory-Klasse, die Event-Handler hatte, die gelegentlich klassenweite Daten verwendeten, um Informationen zu erhalten, und einige dieser Informationen waren wert- oder abrufbar. (Das war für ein Django-Formular.) Also war das "Callable" ein vom Benutzer übergebenes Lambda, das mit self.value() oder klass.value() aufgerufen werden musste, aber value war eine ungebundene Funktion (Lambda oder nicht).

Verwandte Themen