36 Stimmen

varargs in Lambda-Funktionen in Python

Ist es möglich, dass eine Lambda-Funktion eine variable Anzahl von Argumenten hat? Ich möchte z.B. eine Metaklasse schreiben, die für jede Methode einer anderen Klasse eine Methode erstellt und diese neu erstellte Methode gibt den entgegengesetzten Wert der ursprünglichen Methode zurück und hat die gleiche Anzahl von Argumenten. Und ich möchte dies mit einer Lambda-Funktion tun. Wie kann ich die Argumente übergeben? Ist das möglich?

class Negate(type):
    def __new__(mcs, name, bases, _dict):
        extended_dict = _dict.copy()
        for (k, v) in _dict.items():
            if hasattr(v, '__call__'):
                extended_dict["not_" + k] = lambda s, *args, **kw:  not v(s, *args, **kw)
        return type.__new__(mcs, name, bases, extended_dict)

class P(metaclass=Negate):
    def __init__(self, a):
        self.a = a

    def yes(self):
        return True

    def maybe(self, you_can_chose):
        return you_can_chose

Aber das Ergebnis ist völlig falsch:

>>>p = P(0)
>>>p.yes()
True
>>>p.not_yes()     # should be False
Traceback (most recent call last):
  File "<pyshell#150>", line 1, in <module>
    p.not_yes()
  File "C:\Users\Desktop\p.py", line 51, in <lambda>
    extended_dict["not_" + k] = lambda s, *args, **kw:  not v(s, *args, **kw)
TypeError: __init__() takes exactly 2 positional arguments (1 given)
>>>p.maybe(True)
True
>>>p.not_maybe(True)     #should be False
True

42voto

interjay Punkte 101333

Es ist kein Problem, varargs in Lambda-Funktionen zu verwenden. Das Problem ist hier ein anderes:

Das Problem ist, dass die Lambda-Variable auf die Schleifenvariable v . Aber zum Zeitpunkt des Aufrufs des Lambdas ist der Wert von v geändert hat und das Lambda die falsche Funktion aufruft. Das ist immer etwas, worauf man achten muss, wenn man ein Lambda in einer Schleife definiert.

Sie können dies beheben, indem Sie eine zusätzliche Funktion erstellen, die den Wert von v in einer Schließung:

def create_not_function(v):
    return lambda s, *args, **kw:  not v(s, *args, **kw)

for (k, v) in _dict.items():
    if hasattr(v, '__call__'):
        extended_dict["not_" + k] = create_not_function(v)

37voto

Joe Koberg Punkte 23526

Ja.

>>> l = lambda *x: print(x)
>>> l(1,2,3)
(1, 2, 3)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X