Ich habe eine Liste von Objekten und möchte alle Objekte entfernen, die leer sind, bis auf eines, using filter
und einen lambda
Ausdruck.
Zum Beispiel, wenn die Eingabe ist:
[Object(name=""), Object(name="fake_name"), Object(name="")]
... dann sollte die Ausgabe sein:
[Object(name=""), Object(name="fake_name")]
Gibt es eine Möglichkeit, einem lambda
Ausdruck eine Zuweisung hinzuzufügen ? Beispielsweise:
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
Antworten:
Der
:=
in Python 3.8 hinzugefügte Zuweisungsausdrucksoperator unterstützt die Zuweisung innerhalb von Lambda-Ausdrücken. Dieser Operator kann aus syntaktischen Gründen nur in einem Ausdruck in Klammern(...)
, Klammern[...]
oder Klammern angezeigt{...}
werden. Zum Beispiel können wir Folgendes schreiben:In Python 2 war es möglich, lokale Zuweisungen als Nebeneffekt des Listenverständnisses durchzuführen.
In Ihrem Beispiel ist es jedoch nicht möglich, eines dieser Elemente zu verwenden, da sich Ihre Variable
flag
in einem äußeren Bereich befindet, nicht imlambda
Bereich des. Dies hat nichts mitlambda
dem allgemeinen Verhalten in Python 2 zu tun. Mit Python 3 können Sie dies mit demnonlocal
Schlüsselwort indef
s umgehen,nonlocal
können jedoch nicht inlambda
s verwendet werden.Es gibt eine Problemumgehung (siehe unten), aber während wir beim Thema sind ...
In einigen Fällen können Sie dies verwenden, um alles innerhalb eines
lambda
:Bitte nicht.
... zurück zu Ihrem ursprünglichen Beispiel: Obwohl Sie der
flag
Variablen im äußeren Bereich keine Zuweisungen vornehmen können, können Sie den zuvor zugewiesenen Wert mithilfe von Funktionen ändern.Zum Beispiel
flag
könnte ein Objekt sein, dessen.value
wir setzen mitsetattr
:Wenn wir das obige Thema anpassen wollten, könnten wir ein Listenverständnis verwenden, anstatt
setattr
:Aber wirklich, in seriösem Code sollten Sie immer eine reguläre Funktionsdefinition anstelle einer verwenden,
lambda
wenn Sie eine äußere Zuweisung vornehmen möchten.quelle
.setattr()
und gleich ( Wörterbücher sollten es auch tun), um Nebenwirkungen in Funktionscode zu hacken, cooler Code von @JeremyBanks wurde gezeigt :)assignment operator
!Sie können den Status in einem
filter
/lambda
Ausdruck nicht wirklich beibehalten (es sei denn, Sie missbrauchen den globalen Namespace). Sie können jedoch etwas Ähnliches erreichen, indem Sie das akkumulierte Ergebnis in einemreduce()
Ausdruck weitergeben:Sie können den Zustand natürlich ein wenig anpassen. In diesem Fall werden Duplikate herausgefiltert, aber Sie können
a.count("")
beispielsweise auch nur leere Zeichenfolgen einschränken.Unnötig zu sagen, dass Sie dies tun können, aber Sie sollten es wirklich nicht tun. :) :)
Schließlich können Sie alles in reinem Python tun
lambda
: http://vanderwijk.info/blog/pure-lambda-calculus-python/quelle
Es ist nicht erforderlich, ein Lambda zu verwenden, wenn Sie alle Nullen entfernen und eines zurücksetzen können, wenn sich die Eingabegröße ändert:
quelle
output = [x for x in input if x.name]
.Eine normale Zuweisung (
=
) ist innerhalb eineslambda
Ausdrucks nicht möglich , obwohl es möglich ist, verschiedene Tricks mitsetattr
und mit Freunden auszuführen .Die Lösung Ihres Problems ist jedoch recht einfach:
was dir geben wird
Wie Sie sehen können, wird die erste leere Instanz anstelle der letzten beibehalten. Wenn Sie stattdessen die letzte benötigen, kehren Sie die Liste um, in die Sie gehen
filter
, und kehren Sie die Liste um, aus der Folgendes hervorgehtfilter
:was dir geben wird
Eines ist zu beachten: Damit dies mit beliebigen Objekten funktioniert, müssen diese Objekte ordnungsgemäß implementiert werden
__eq__
und__hash__
wie hier erläutert .quelle
UPDATE :
oder mit
filter
undlambda
:Vorherige Antwort
OK, verwenden Sie Filter und Lambda?
Es scheint, als wäre dies besser mit einem Wörterbuchverständnis bedient,
Ich denke, der Grund, warum Python keine Zuweisung in einem Lambda zulässt, ist ähnlich wie der Grund, warum es keine Zuweisung in einem Verständnis zulässt, und das hat etwas damit zu tun, dass diese Dinge nebenbei ausgewertet werden
C
und uns somit eine geben können Geschwindigkeitssteigerung. Zumindest ist das mein Eindruck, nachdem ich einen von Guidos Essays gelesen habe .Ich vermute, dies würde auch gegen die Philosophie verstoßen, einen richtigen Weg zu haben, um irgendetwas in Python zu tun.
quelle
TL; DR: Wenn Sie funktionale Redewendungen verwenden, ist es besser, funktionalen Code zu schreiben
Wie viele Leute darauf hingewiesen haben, ist in Python die Zuweisung von Lambdas nicht erlaubt. Wenn Sie funktionale Redewendungen verwenden, sollten Sie im Allgemeinen besser funktional denken, was bedeutet, dass nach Möglichkeit keine Nebenwirkungen und keine Aufgaben auftreten.
Hier ist eine funktionale Lösung, die ein Lambda verwendet. Ich habe das Lambda der
fn
Klarheit halber zugewiesen (und weil es etwas langwierig wurde).Sie können sich auch mit Iteratoren und nicht mit Listen befassen, indem Sie die Dinge ein wenig ändern. Sie haben auch verschiedene Importe.
Sie können den Code jederzeit umbenennen, um die Länge der Anweisungen zu verringern.
quelle
Wenn
flag = True
wir stattdessen einen Import durchführen können, dann entspricht dies meiner Meinung nach den Kriterien:Oder vielleicht ist der Filter besser geschrieben als:
Oder nur für einen einfachen Booleschen Wert ohne Importe:
quelle
Die pythonische Methode zum Verfolgen des Status während der Iteration sind Generatoren. Der itertools-Weg ist meiner Meinung nach ziemlich schwer zu verstehen, und der Versuch, Lambdas zu hacken, um dies zu tun, ist einfach albern. Ich würde versuchen:
Insgesamt übertrifft die Lesbarkeit jedes Mal die Kompaktheit.
quelle
Nein, Sie können eine Zuordnung aufgrund ihrer eigenen Definition nicht in ein Lambda einfügen. Wenn Sie mit funktionaler Programmierung arbeiten, müssen Sie davon ausgehen, dass Ihre Werte nicht veränderbar sind.
Eine Lösung wäre der folgende Code:
quelle
Wenn Sie ein Lambda benötigen, um sich den Status zwischen Aufrufen zu merken, würde ich entweder eine im lokalen Namespace deklarierte Funktion oder eine Klasse mit einer Überladung empfehlen
__call__
. Jetzt, da alle meine Warnungen vor dem, was Sie versuchen, aus dem Weg sind, können wir eine tatsächliche Antwort auf Ihre Frage erhalten.Wenn Sie Ihr Lambda wirklich benötigen, um zwischen den Aufrufen Speicher zu haben, können Sie es wie folgt definieren:
Dann brauchen Sie nur passieren
f
zufilter()
. Wenn Sie es wirklich brauchen, können Sie den Wert vonflag
mit den folgenden zurückerhalten :Alternativ können Sie den globalen Namespace ändern, indem Sie das Ergebnis von ändern
globals()
. Leider können Sie den lokalen Namespace nicht auf die gleiche Weise ändern, wie das Ändern des Ergebnisses vonlocals()
den lokalen Namespace nicht beeinflusst.quelle
(let ((var 42)) (lambda () (setf var 43)))
.Sie können eine Bindefunktion verwenden, um ein Lambda mit mehreren Pseudoanweisungen zu verwenden. Anschließend können Sie eine Wrapper-Klasse für ein Flag verwenden, um die Zuweisung zu aktivieren.
quelle
Eine Art chaotischer Workaround, aber die Zuweisung in Lambdas ist sowieso illegal, also spielt es keine Rolle. Sie können die integrierte
exec()
Funktion verwenden, um die Zuweisung innerhalb des Lambda auszuführen, wie in diesem Beispiel:quelle
Zunächst müssen Sie für Ihren Job keine lokale Zuordnung verwenden. Überprüfen Sie einfach die obige Antwort
Zweitens ist es einfach, mit local () und globals () die Variablentabelle abzurufen und dann den Wert zu ändern
Überprüfen Sie diesen Beispielcode:
Wenn Sie das Add eine globale Variable auf Ihre environ ändern müssen, versuchen zu ersetzen Einheimischen () mit Globals ()
Pythons List Comp ist cool, aber die meisten der drei Projekte akzeptieren dies nicht (wie flask: [)
hoffe es könnte helfen
quelle
locals()
, es wird ausdrücklich in der Dokumentation angegeben, dass eine Änderung nicht den lokalen Bereich ändert (oder zumindest nicht immer).globals()
funktioniert dagegen wie erwartet.globals()
. pastebin.com/5Bjz1mR4 (getestet in 2.6 und 3.2) beweist es.