Ich habe eine Methode, die 4 andere Methoden nacheinander aufruft, um nach bestimmten Bedingungen zu suchen, und sofort zurückkehrt (ohne die folgenden zu prüfen), wenn man etwas Wahres zurückgibt.
def check_all_conditions():
x = check_size()
if x:
return x
x = check_color()
if x:
return x
x = check_tone()
if x:
return x
x = check_flavor()
if x:
return x
return None
Dies scheint eine Menge Gepäckcode. Anstelle jeder zweizeiligen if-Anweisung würde ich lieber Folgendes tun:
x and return x
Aber das ist ungültiges Python. Vermisse ich hier eine einfache, elegante Lösung? In dieser Situation können diese vier Prüfmethoden übrigens teuer sein, daher möchte ich sie nicht mehrmals aufrufen.
python
if-statement
Bernard
quelle
quelle
x and return x
ist besser alsif x: return x
? Letzteres ist weitaus besser lesbar und damit wartbar. Sie sollten sich nicht zu viele Gedanken über die Anzahl der Zeichen oder Zeilen machen. Lesbarkeit zählt. Sie haben sowieso genau die gleiche Anzahl von Nicht-Leerzeichen, und wenn Sie es wirklich müssen,if x: return x
funktionieren sie in nur einer Zeile einwandfrei.x
(im Gegensatz zubool(x)
) zurück. Ich denke, es ist sicher anzunehmen, dass die Funktionen von OP alles zurückgeben können, und er möchte als erstes alles, was wahr ist.Antworten:
Sie könnten eine Schleife verwenden:
Dies hat den zusätzlichen Vorteil, dass Sie jetzt die Anzahl der Bedingungen variabel machen können.
Sie können
map()
+ verwendenfilter()
(die Python 3-Versionen, verwenden Sie diefuture_builtins
Versionen in Python 2), um den ersten solchen übereinstimmenden Wert zu erhalten:aber ob dies besser lesbar ist, ist umstritten.
Eine andere Option ist die Verwendung eines Generatorausdrucks:
quelle
any
anstelle der Schleife verwenden.return any(condition() for condition in conditions)
any
hat fast die gleiche Implementierung im Inneren. Aber es sieht viel besser aus, bitteconditions
undarguments
? Dies ist meiner Meinung nach viel schlimmer als der ursprüngliche Code, dessen Analyse durch meinen Brainparser etwa 10 Sekunden dauert.return next((check for check in checks if check), None)
.Alternativ zu Martijns feiner Antwort könnten Sie verketten
or
. Dies gibt den ersten Wahrheitswert zurück, oderNone
wenn es keinen Wahrheitswert gibt:Demo:
quelle
\
jeden Scheck in eine eigene Zeile setzen können.\
es nicht, die logische Linie zu erweitern. Verwenden Sie stattdessen nach Möglichkeit Klammern. alsoreturn (....)
mit nach Bedarf eingefügten Zeilenumbrüchen. Trotzdem wird das eine lange logische Linie sein.Ändere es nicht
Es gibt andere Möglichkeiten, dies zu tun, wie die verschiedenen anderen Antworten zeigen. Keiner ist so klar wie Ihr Originalcode.
quelle
:
, da ichif x: return x
das für ziemlich gut halte und die Funktion dadurch kompakter aussieht. Aber das kann nur ich sein.or
als Timgeb ist eine richtige und gut verstandene Redewendung. Viele Sprachen haben dies; vielleicht , wenn es heißtorelse
es noch klar, aber auch die gute alteor
(oder||
in anderen Sprachen) ist gemeint als Alternative verstanden werden , um zu versuchen , wenn die erste „funktioniert nicht.“or
unpythonisch oder in irgendeiner Weise verschleiert gehört, aber das ist sowieso Ansichtssache - wie es sein sollte.In praktisch der gleichen Antwort wie Timgeb, aber Sie könnten Klammern für eine schönere Formatierung verwenden:
quelle
Nach dem Gesetz von Curly können Sie diesen Code lesbarer machen, indem Sie zwei Probleme aufteilen:
in zwei Funktionen:
Dies vermeidet:
... unter Beibehaltung eines linearen, leicht lesbaren Flusses.
Abhängig von Ihren besonderen Umständen können Sie wahrscheinlich auch noch bessere Funktionsnamen finden, die die Lesbarkeit verbessern.
quelle
return None
nicht erforderlich ist, da FunktionenNone
standardmäßig zurückgegeben werden. Es ist jedoch nichts Falsches daran,None
explizit zurückzukehren, und ich finde es gut, dass Sie sich dafür entschieden haben.Dies ist eine Variante von Martijns erstem Beispiel. Es wird auch der Stil "Sammlung von Callables" verwendet, um Kurzschlüsse zu ermöglichen.
Anstelle einer Schleife können Sie die eingebaute verwenden
any
.Beachten Sie, dass
any
ein Boolescher Wert zurückgegeben wird. Wenn Sie also den genauen Rückgabewert der Prüfung benötigen, funktioniert diese Lösung nicht.any
nicht unterscheiden zwischen14
,'red'
,'sharp'
,'spicy'
wird als Rückgabewerte, sie alle als zurückgeschickt werdenTrue
.quelle
next(itertools.ifilter(None, (c() for c in conditions)))
den tatsächlichen Wert ermitteln, ohne ihn in einen Booleschen Wert umzuwandeln.any
tatsächlich Kurzschluss?x = bar(); if x: return x;
Haben Sie darüber nachgedacht,
if x: return x
alles in eine Zeile zu schreiben ?Dies ist nicht weniger repetitiv als das, was Sie hatten, aber IMNSHO liest es sich ziemlich flüssiger.
quelle
Ich bin ziemlich überrascht, dass niemand das eingebaute Gerät erwähnt hat, das
any
für diesen Zweck hergestellt wurde:Beachten Sie, dass diese Implementierung zwar wahrscheinlich die klarste ist, jedoch alle Überprüfungen auswertet, auch wenn es sich um die erste handelt
True
.Wenn Sie bei der ersten fehlgeschlagenen Prüfung wirklich anhalten müssen, sollten Sie überlegen, mit
reduce
welcher Methode eine Liste in einen einfachen Wert konvertiert werden soll:In deinem Fall:
lambda a, f: a or f()
ist die Funktion, die prüft, ob entweder der Akkua
oder die aktuelle Prüfung vorhandenf()
istTrue
. Beachten Sie, dass , wenna
istTrue
,f()
werden nicht bewertet.checks
enthält Prüffunktionen (derf
Artikel aus dem Lambda)False
ist der Anfangswert, sonst würde keine Prüfung stattfinden und das Ergebnis wäre immerTrue
any
undreduce
sind grundlegende Werkzeuge für die funktionale Programmierung. Ich empfehle Ihnen dringend, diese zu trainieren, undmap
das ist auch großartig!quelle
any
funktioniert nur, wenn die Prüfungen tatsächlich einen booleschen Wert zurückgeben, wörtlichTrue
oderFalse
, aber die Frage gibt das nicht an. Sie müssen verwendenreduce
, um den tatsächlichen Wert zurückzugeben, der von der Prüfung zurückgegeben wird. Es ist auch leicht genug zu vermeiden, alle Überprüfungen mitany
einem Generator auszuwerten , zany(c() for c in (check_size, check_color, check_tone, check_flavor))
. Wie in Leonhards Antwortreduce
. Wie @DavidZ glaube ich, dass Ihre Lösung mitany
einen Generator verwenden sollte, und es muss darauf hingewiesen werden, dass es auf die RückgabeTrue
oder beschränkt istFalse
.any
mit wahrheitsgemäßen Werten:any([1, "abc", False]) == True
undany(["", 0]) == False
any
nur funktioniert , wenn tatsächliche boolesche Werte von den Prüffunktionen zurückgegeben werden.Wenn Sie dieselbe Codestruktur wünschen, können Sie ternäre Anweisungen verwenden!
Ich denke, das sieht gut und klar aus, wenn man es sich ansieht.
Demo:
quelle
x if x else <something>
kann nur aufx or <something>
Für mich ist die beste Antwort die von @ phil-frost, gefolgt von @ wayne-werner's.
Was ich interessant finde, ist, dass niemand etwas darüber gesagt hat, dass eine Funktion viele verschiedene Datentypen zurückgibt, was es dann zwingend erforderlich macht, den Typ von x selbst zu überprüfen, um weitere Arbeiten durchzuführen.
Also würde ich die Antwort von @ PhilFrost mit der Idee mischen, einen einzigen Typ beizubehalten:
Beachten Sie, dass dies
x
als Argument übergeben wird, aber auchall_conditions
als übergebener Generator für Überprüfungsfunktionen verwendet wird, bei denen alle einex
zu überprüfende Funktion erhalten undTrue
oder zurückgebenFalse
. Durch die Verwendung vonfunc
mitall_conditions
als Standardwert, können Sie verwendenassessed_x(x)
, oder Sie können über einen weiteren personalisierten Generator übergebenfunc
.Auf diese Weise erhalten Sie,
x
sobald ein Scheck bestanden wurde, aber es wird immer der gleiche Typ sein.quelle
Im Idealfall würde ich die
check_
Funktionen neu schreiben , um sie zurückzugeben,True
oderFalse
nicht einen Wert. Ihre Schecks werden dannVorausgesetzt
x
, Ihre Funktion ist nicht unveränderlich, kann Ihre Funktion sie dennoch ändern (obwohl sie sie nicht neu zuweisen kann) - aber eine aufgerufene Funktioncheck
sollte sie ohnehin nicht wirklich ändern .quelle
Eine kleine Variation von Martijns erstem Beispiel oben, die das if innerhalb der Schleife vermeidet:
quelle
Status or c()
Überspringt / kurzschließt die Auswertung von Anrufen,c()
wenn diesStatus
wahr ist, sodass der Code in dieser Antwort nicht mehr Funktionen als den OP-Code aufzurufen scheint. stackoverflow.com/questions/2580136/…Ich mag @ timgeb's. In der Zwischenzeit möchte ich hinzufügen, dass das Ausdrücken
None
in derreturn
Anweisung nicht erforderlich ist, da die Sammlungor
getrennter Anweisungen ausgewertet wird und die ersten nicht null, nicht leer, keine keine zurückgegeben werden und wenn keine vorhandenNone
sind, zurückgegeben wird ob es eine gibtNone
oder nicht!Meine
check_all_conditions()
Funktion sieht also so aus:Mit
timeit
mit habenumber=10**7
ich mir die Laufzeit einiger Vorschläge angesehen. Zum Vergleich habe ich dierandom.random()
Funktion nur verwendet , um eine Zeichenfolge zurückzugeben oderNone
basierend auf Zufallszahlen. Hier ist der gesamte Code:Und hier sind die Ergebnisse:
quelle
Dieser Weg ist etwas außerhalb des Rahmens, aber ich denke, das Endergebnis ist einfach, lesbar und sieht gut aus.
Die Grundidee ist
raise
eine Ausnahme, wenn eine der Funktionen als wahr bewertet wird und das Ergebnis zurückgibt. So könnte es aussehen:Sie benötigen eine
assertFalsey
Funktion, die eine Ausnahme auslöst, wenn eines der aufgerufenen Funktionsargumente als wahr bewertet wird:Das Obige könnte geändert werden, um auch Argumente für die zu bewertenden Funktionen bereitzustellen.
Und natürlich brauchst du das
TruthyException
selbst. Diese Ausnahme liefert dieobject
, die die Ausnahme ausgelöst hat:Sie können die ursprüngliche Funktion natürlich in etwas Allgemeineres verwandeln:
Dies kann etwas langsamer sein, da Sie sowohl eine
if
Anweisung verwenden als auch eine Ausnahme behandeln. Die Ausnahme wird jedoch nur maximal einmal behandelt, sodass der Leistungseinbruch gering sein sollte, es sei denn, Sie erwarten, dass Sie die Prüfung ausführen undTrue
viele, viele tausend Male einen Wert erhalten.quelle
StopIteration
ist ein ziemlich gutes Beispiel: Jedes Mal, wenn Sie ein iterables Element erschöpfen, wird eine Ausnahme ausgelöst. Das, was Sie vermeiden möchten, ist, immer wieder Ausnahmen auszulösen, die teuer werden würden. Aber es einmal zu tun ist nicht.Die pythonische Methode ist entweder die Verwendung von reduct (wie bereits erwähnt) oder itertools (wie unten gezeigt), aber es scheint mir, dass die einfache Verwendung des Kurzschlusses des
or
Operators einen klareren Code erzeugtquelle
Ich werde hier reinspringen und habe noch nie eine einzige Zeile Python geschrieben, aber ich gehe davon aus, dass sie
if x = check_something(): return x
gültig ist?wenn ja:
quelle
if ( x := check_size() ) :
für denselben Effekt schreiben können.Oder verwenden Sie
max
:quelle
Ich habe in der Vergangenheit einige interessante Implementierungen von Switch / Case-Anweisungen mit Diktaten gesehen, die mich zu dieser Antwort geführt haben. Anhand des von Ihnen angegebenen Beispiels erhalten Sie Folgendes. (Es ist Wahnsinn
using_complete_sentences_for_function_names
, alsocheck_all_conditions
wird umbenannt instatus
. Siehe (1))Die Auswahlfunktion macht das Aufrufen jedes einzelnen überflüssig
check_FUNCTION
zweimalige überflüssig, dh Sie vermeiden dies,check_FUNCTION() if check_FUNCTION() else next
indem Sie eine weitere Funktionsebene hinzufügen. Dies ist nützlich für lang laufende Funktionen. Die Lambdas im Diktat verzögern die Ausführung ihrer Werte bis zur while-Schleife.Als Bonus können Sie die Ausführungsreihenfolge ändern und sogar einige der Tests durch Ändern überspringen
k
unds
k='c',s={'c':'b','b':None}
die Anzahl der Tests z. B. reduzieren und die ursprüngliche Verarbeitungsreihenfolge umkehren.Das
timeit
Kollegen feilschen möglicherweise über die Kosten für das Hinzufügen einer oder zweier zusätzlicher Ebenen zum Stapel und die Kosten für das Nachschlagen des Diktats, aber Sie scheinen sich mehr um die Schönheit des Codes zu kümmern.Alternativ könnte eine einfachere Implementierung die folgende sein:
quelle
check_no/some/even/prime/every_third/fancy_conditions
aber nur diese eine Funktion so , warum es nicht nennenstatus
oder , wenn man darauf bestehtcheck_status
. Die Verwendung_all_
ist überflüssig, er gewährleistet nicht die Integrität des Universums. Bei der Benennung sollten sicherlich konsistente Schlüsselwörter verwendet werden, wobei der Namensabstand nach Möglichkeit genutzt wird. Lange Sätze dienen am besten als Dokumentzeichenfolgen. Man braucht selten mehr als 8-10 Zeichen, um etwas kurz und bündig zu beschreiben.check_all_conditions
ein schlechter Name, weil nicht alle Bedingungen überprüft werden, ob eine wahr ist. Ich würde so etwas benutzenmatches_any_condition
.