Betrachten Sie den folgenden Python2-Code
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Dies wird in Python3 nicht unterstützt und ich muss Folgendes tun:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
Das ist sehr hässlich. Wenn das Lambda eine Funktion wäre, könnte ich es tun
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
Durch das Entfernen dieser Funktion in Python3 wird der Code gezwungen, entweder die hässliche Methode (mit magischen Indizes) auszuführen oder unnötige Funktionen zu erstellen (am störendsten ist es, sich gute Namen für diese unnötigen Funktionen auszudenken).
Ich denke, die Funktion sollte zumindest nur Lambdas hinzugefügt werden. Gibt es eine gute Alternative?
Update: Ich verwende den folgenden Helfer, um die Idee in der Antwort zu erweitern
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Update2: Eine sauberere Version fürstar
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
python
python-3.x
balki
quelle
quelle
lambda
, dass Sie vollständig aus der Sprache entfernt werden, als Änderungen rückgängig zu machen, die die Verwendung erschwert haben. Sie können jedoch versuchen, auf Python-Ideen zu posten, wenn Sie den Wunsch äußern möchten, die Funktion wieder hinzuzufügen.lambda
im gleichen Geist wie er widersetztmap
,reduce
undfilter
.lambda
wurde für die Entfernung in py3k geplant, da es im Grunde eine Plage für die Sprache ist. Aber niemand konnte sich auf eine geeignete Alternative für die Definition anonymer Funktionen einigen, also warf Guido schließlich niedergeschlagen die Arme hoch und das war's.map
undfilter
am besten durch Verständnis ersetzt werden, mag ichreduce
)Antworten:
Nein, es gibt keinen anderen Weg. Du hast alles abgedeckt. Der Weg wäre, dieses Problem auf die Python-Ideen-Mailingliste zu setzen , aber seien Sie bereit, dort viel zu streiten, um etwas Traktion zu gewinnen.
Um nicht zu sagen, dass es keinen Ausweg gibt, könnte ein dritter Weg darin bestehen, eine weitere Ebene von Lambda-Aufrufen zu implementieren, um nur die Parameter zu entfalten - aber das wäre gleichzeitig ineffizienter und schwerer zu lesen als Ihre beiden Vorschläge:
Aktualisieren Sie Python 3.8
Ab sofort ist Python 3.8 alpha1 verfügbar und PEP 572-Zuweisungsausdrücke sind implementiert.
Wenn man also einen Trick verwendet, um mehrere Ausdrücke in einem Lambda auszuführen - normalerweise mache ich das, indem ich ein Tupel erstelle und nur die letzte Komponente davon zurückgebe, ist es möglich:
Man sollte bedenken, dass diese Art von Code selten lesbarer oder praktischer ist als eine volle Funktion. Dennoch gibt es mögliche Verwendungszwecke - wenn es verschiedene Einzeiler gibt, die damit arbeiten würden
point
, könnte es sich lohnen, ein benanntes Tupel zu haben und den Zuweisungsausdruck zu verwenden, um die eingehende Sequenz effektiv in das benannte Tupel "umzuwandeln":quelle
def
in der Frage unter der Nummer genannten zu verwendensome_name_to_think-of
.key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
Laut http://www.python.org/dev/peps/pep-3113/ sind das Auspacken von Tupeln weg und
2to3
werden sie wie folgt übersetzen:Welches ist ziemlich ähnlich zu Ihrer Implementierung.
quelle
Ich kenne keine guten allgemeinen Alternativen zum Entpackungsverhalten der Python 2-Argumente. Hier sind einige Vorschläge, die in einigen Fällen nützlich sein können:
wenn Ihnen kein Name einfällt; Verwenden Sie den Namen des Schlüsselwortparameters:
Sie können sehen, ob a
namedtuple
Ihren Code lesbarer macht, wenn die Liste an mehreren Stellen verwendet wird:quelle
lambda (x, y):
undlambda x, y:
auf den ersten Blick nicht offensichtlich ist.Während die Destrukturierungsargumente in Python3 entfernt wurden, wurden sie nicht aus dem Verständnis entfernt. Es ist möglich, es zu missbrauchen, um ein ähnliches Verhalten in Python 3 zu erhalten. Im Wesentlichen nutzen wir die Tatsache, dass Co-Routinen es uns ermöglichen, Funktionen auf den Kopf zu stellen, und Yield ist keine Aussage und daher innerhalb von Lambdas zulässig.
Beispielsweise:
Im Vergleich zur akzeptierten Antwort der Verwendung eines Wrappers kann diese Lösung die Argumente vollständig zerstören, während der Wrapper nur die erste Ebene zerstört. Das ist,
Im Vergleich zu
Alternativ kann man auch machen
Oder etwas besser
Dies soll nur darauf hinweisen, dass dies möglich ist und nicht als Empfehlung verstanden werden sollte.
quelle
Basierend auf dem Cuadue-Vorschlag und Ihrem Kommentar zum Auspacken, der immer noch im Verständnis vorhanden ist, können Sie Folgendes verwenden
numpy.argmin
:quelle
Eine andere Möglichkeit besteht darin, es in einen Generator zu schreiben, der ein Tupel erzeugt, bei dem der Schlüssel das erste Element ist. Tupel werden von Anfang bis Ende verglichen, sodass das Tupel mit dem kleinsten ersten Element zurückgegeben wird. Sie können dann in das Ergebnis indizieren, um den Wert zu erhalten.
quelle
Überlegen Sie, ob Sie das Tupel zuerst auspacken müssen:
oder ob Sie beim Auspacken explizite Namen angeben müssen:
quelle
Ich denke, die bessere Syntax ist
x * x + y * y let x, y = point
, dass daslet
Schlüsselwort sorgfältiger ausgewählt werden sollte.Das doppelte Lambda ist die nächstgelegene Version.
lambda point: (lambda x, y: x * x + y * y)(*point)
Ein Funktionshelfer hoher Ordnung wäre nützlich, wenn wir ihm einen richtigen Namen geben.
quelle