Mehrzeilige Bedingungen in 'if'-Anweisungen gestalten? [geschlossen]


674

Manchmal breche ich lange Bedingungen in ifs in mehrere Zeilen. Der naheliegendste Weg, dies zu tun, ist:

  if (cond1 == 'val1' and cond2 == 'val2' and
      cond3 == 'val3' and cond4 == 'val4'):
      do_something

Ist optisch nicht sehr sehr ansprechend, da sich die Aktion mit den Bedingungen verbindet. Es ist jedoch der natürliche Weg, die korrekte Python-Einrückung von 4 Leerzeichen zu verwenden.

Im Moment benutze ich:

  if (    cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
      do_something

Das ist aber nicht sehr hübsch. :-)

Können Sie einen alternativen Weg empfehlen?


2
Wenn Ihr Editor das Python-Paket pep8 verwendet , um zu erkennen, wann vor PEP8- Verstößen gewarnt werden muss , müssen Sie entweder den E125-Fehler deaktivieren oder eine Formatierungslösung finden, die die pep8Kriterien des Pakets erfüllt. In pep8der Ausgabe Nr. 126 des Pakets geht es darum, das Paket so zu reparieren, dass es genau der PEP8-Spezifikation entspricht. Die Diskussion für das Problem enthält einige Stilvorschläge, die auch hier zu sehen sind.
Akaihola

1
Beachten Sie, dass pep8 für das erste Beispiel "E129 visuell eingerückte Zeile mit demselben Einzug wie die nächste logische Zeile" auslöst.
Taylor Edmiston

Diese Frage ist sehr alt und hat eine Menge Ansichten, aber sie basiert eindeutig auf Meinungen. Die Sprache "ist nicht sehr ansprechend" und "ist nicht sehr hübsch" legt die Kriterien fest, nach denen die angeblich richtige Antwort am besten mit der ästhetischen Präferenz des Fragestellers übereinstimmt (dh einer Meinung). Ich könnte genau die gleiche Frage stellen und behaupten, es sei kein Duplikat, weil mein ästhetischer Geschmack es als unterschiedlich qualifiziert und zu einer anderen "richtigen" Antwort führen wird.
Z4-Tier

@ Z4-Tier: Ja, es basiert auf Meinungen. Aber es wurde vor 12 Jahren gefragt. SO war damals ein anderer, freundlicherer Ort. In letzter Zeit hat es Downvotes gesammelt, seit sich die Standards von SO geändert haben. Trotzdem hoffe ich, dass es, nachdem es> 1 Million Mal angesehen wurde, der Welt mehr nützt als schadet. Ich kann sicherlich Leute sehen, die sich heute über dieselbe Frage wundern, sie googeln, auf diese Diskussion stoßen und es nützlich finden, ihr Denken zu kalibrieren. Es stehen mehrere hoch bewertete Antworten zur Auswahl.
Eli Bendersky

@EliBendersky stimme voll und ganz zu. Es ist, als ob SO eine anhaltende Identitätskrise hat: Obwohl es eindeutig nicht "den Regeln" entspricht (die Anzahl der gültigen Antworten ist ein Beweis dafür), ist es genauso klar, dass es einen Mehrwert schafft. Wenn alle Dinge gleich sind, würde ich lieber mit jemandem zusammenarbeiten, der artikulierbare und begründete Ansichten zum Codierungsstil entwickelt hat, auch wenn sich ihre Ansichten von meinen unterscheiden.
Z4-Tier

Antworten:


747

Sie müssen in Ihrer zweiten bedingten Zeile keine 4 Leerzeichen verwenden. Vielleicht verwenden:

if (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

Vergessen Sie auch nicht, dass das Leerzeichen flexibler ist, als Sie vielleicht denken:

if (   
       cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
if    (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

Beide sind allerdings ziemlich hässlich.

Vielleicht die Klammern verlieren (der Style Guide rät jedoch davon ab)?

if cond1 == 'val1' and cond2 == 'val2' and \
   cond3 == 'val3' and cond4 == 'val4':
    do_something

Dies gibt Ihnen zumindest eine gewisse Differenzierung.

Oder auch:

if cond1 == 'val1' and cond2 == 'val2' and \
                       cond3 == 'val3' and \
                       cond4 == 'val4':
    do_something

Ich glaube ich bevorzuge:

if cond1 == 'val1' and \
   cond2 == 'val2' and \
   cond3 == 'val3' and \
   cond4 == 'val4':
    do_something

Hier ist der Style Guide , der (seit 2010) die Verwendung von Klammern empfiehlt.


45
Beachten Sie, dass die nachfolgenden \ Lösungen von PEP 8 nicht empfohlen werden. Ein Grund dafür ist, dass ein versehentlich nach a \ hinzugefügtes Leerzeichen möglicherweise nicht in Ihrem Editor angezeigt wird und der Code syntaktisch falsch wird.
Eric O Lebigot

14
Dies ist falsch, heißt es im Styleguide: "Lange Zeilen können über mehrere Zeilen unterbrochen werden, indem Ausdrücke in Klammern eingeschlossen werden. Diese sollten bevorzugt verwendet werden, anstatt einen Backslash für die Zeilenfortsetzung zu verwenden." Sie können dies hier sehen: python.org/dev/peps/pep-0008/#maximum-line-length
joshcartme

8
@joshcartme Das PEP wurde unter hg.python.org/peps/rev/7a48207aaab6 geändert , um Backslashes explizit zu verhindern. Ich werde die Antwort aktualisieren.
Harley Holcombe

3
Vielen Dank, es ist wahrscheinlich eine gute Idee, auch Ihre Beispiele zu aktualisieren, da sie jetzt nicht empfohlen werden. Ich habe versucht, dies selbst herauszufinden, und war verwirrt über die Diskrepanz zwischen Ihrer Antwort und dem Styleguide (daher mein Kommentar). Ich habe nicht nur versucht, pedantisch zu sein.
Joshcartme

3
PEP 8 rät jetzt davon ab, nach dem andund zu brechen if.
virtualxtc

124

Ich habe in dem entarteten Fall, in dem es einfach UND und ODER sind, auf Folgendes zurückgegriffen.

if all( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

if any( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

Es rasiert einige Zeichen und macht deutlich, dass die Bedingung nicht subtil ist.


4
Dies ist ein interessanter Ansatz. Behandelt das Problem der langen Bedingungen jedoch nicht
Eli Bendersky

20
Es ist in Ordnung, wenn Sie sich nicht für Kurzschlüsse interessieren.
Constantin

63
Bei Kurzschluss geht es nicht immer um schnell. Obwohl dies keine gute Codierungspraxis ist, verfügen Sie möglicherweise über folgenden Code : if destroy_world and DestroyTheWorld() == world_is_destroyed: .... Großartig, jetzt hast du die Welt durch einen Unfall zerstört. WIE KONNTEST DU?
Aaron

3
Ich bin überrascht, dass dies so viele positive Stimmen hat. Diese Antwort ignoriert die ursprüngliche Frage zum Gestalten mehrzeiliger Bedingungen vollständig .
Przemek D

2
Dieser Ausdruck ist nicht faul. Es ist also nicht gleichbedeutend, wenn auf eine Schutzbedingung möglicherweise eine fehlschlägt.
Eugen-hell

56

Jemand muss sich hier für die Verwendung vertikaler Leerzeichen einsetzen! :) :)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()

Dies macht jeden Zustand deutlich sichtbar. Es ermöglicht auch eine sauberere Expression komplexerer Bedingungen:

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()

Ja, wir tauschen aus Gründen der Klarheit ein bisschen vertikale Immobilien aus. Lohnt sich IMO.


19
Dies scheint weder schön noch PEP8-kompatibel zu sein. PEP8 sagt, dass der bevorzugte Ort zum Umbrechen eines binären Operators (z. andB. sowie or) nach dem Operator und nicht davor liegt.
Chris Medrela

7
@ChristopherMedrela sagt es die Gründe dafür? Ich denke, einen Zeilenumbruch vor dem Logikoperator zu platzieren ist viel klarer
Norill Tempest

4
In der Welt der Knoten ist es durchaus üblich, den Oprerator an die erste Stelle zu setzen. Das Grundprinzip ist, dass wir Dinge auf der linken Seite viel schneller bemerken und lesen als Dinge auf der rechten Seite - zumindest in den westlichen Kulturen. Sehr gültig in JavaScript, wo ein vergessenes Komma stille Fehler verursachen kann.
Tomkwi

11
Tu das bitte nicht. Dies ist nicht nur nicht PEP8der Fall, sondern erschwert auch die Bestimmung der Logikoperation, mit der Sie verketten. Ich würde dies durchfallen lassen, wenn es durch Codeüberprüfung an meinen Schreibtisch käme.
Urda

11
Ab der aktuellen Version von PEP8 wird das Unterbrechen vor oder nach einem Binäroperator als akzeptabel angesehen , und bevor der Operator für neuen Code als besser angesehen wird.
Soren Bjornstad

31

Ich bevorzuge diesen Stil, wenn ich einen schrecklich großen If-Zustand habe:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()

2
+1, um Einrückungen zu behalten, in denen Sie sie verfolgen können. Ich mag Python und benutze es oft, aber ich ärgere mich ständig darüber, dass ich gezwungen bin, nur so einzurücken. Die Mehrfachleitung zerstört die Ästhetik wirklich, auch wenn sie gut gemacht ist.
mächtiger

4
Beachten Sie, dass Ihre andund orOperatoren am Anfang der Zeile gegen PEP 0008 verstoßen , in dem es heißt: "Der bevorzugte Ort, um einen binären Operator zu umgehen , ist nach dem Operator, nicht davor." . Ich mag es jedoch, wenn die schließende Klammer und der Doppelpunkt in einer eigenen Zeile stehen, um die if-Bedingung vom Körper zu trennen (und dies ist durchaus möglich, während Ihre booleschen Operatoren für die Einhaltung von PEP-0008 am Ende der Zeile bleiben).
Mark Amery

8
Stand 2016: For decades the recommended style was to break after binary operators. But this can hurt readability in two ways... In Python code, it is permissible to break before or after a binary operator, as long as the convention is consistent locally. For new code Knuth's style is suggested.(Knuths Stil ist es, die Linie mit dem Operator zu beginnen).
Cowbert

27

Hier ist meine ganz persönliche Einstellung: Lange Bedingungen sind (meiner Ansicht nach) ein Codegeruch, der darauf hindeutet, in eine boolesche Rückgabefunktion / -methode umzuwandeln. Zum Beispiel:

def is_action__required(...):
    return (cond1 == 'val1' and cond2 == 'val2'
            and cond3 == 'val3' and cond4 == 'val4')

Wenn ich nun einen Weg finden würde, mehrzeilige Bedingungen gut aussehen zu lassen, würde ich mich wahrscheinlich damit zufrieden geben, sie zu haben, und das Refactoring überspringen.

Andererseits wirkt es ein Anreiz für das Refactoring, wenn sie meinen ästhetischen Sinn stören.

Mein Fazit ist daher, dass Mehrleitungsbedingungen hässlich aussehen sollten und dies ein Anreiz ist, sie zu vermeiden.


23

Das verbessert sich nicht so sehr, aber ...

allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                 cond3 == 'val3' and cond4 == 'val4')

if allCondsAreOK:
   do_something

1
Interessante Alternative. Aber 2 zusätzliche Zeilen :-)
Eli Bendersky

Würde nicht wirklich so gut in einer iterativen Schleife funktionieren, würde nicht mit Funktionen arbeiten, die etwas tun ... und fair - hässlich sein
Mez

9
Brian, ich bin teilweise anderer Meinung. Die Verwendung von Variablen für Zwischenergebnisse einer Berechnung kann das Verständnis von Code erleichtern und hat in einer kompilierten Sprache keine Auswirkungen auf die Leistung. Es würde wahrscheinlich in Python funktionieren, obwohl ich Python überhaupt nicht verwenden würde, wenn Leistung so wichtig wäre.
Mark Baker

1
@ MarkBaker Ich stimmte dem zu, was Sie geschrieben haben, bis ich Martin Fowlers "Refactoring" las. Er liefert ein hervorragendes Argument dafür, dass solche Zwischenvariablen mehr Schaden als Nutzen verursachen. Sie hemmen das nachfolgende Refactoring. Der Verzicht auf sie führt zu einem funktionaleren Programmierstil, der sich gut für das Refactoring eignet. Das hat mich überrascht, aber ich glaube, er hat Recht und ist seitdem bestrebt, unnötige Zwischenprodukte wie dieses aus meinem Code zu entfernen - auch wenn sie mehr als einmal verwendet werden.
Jonathan Hartley

2
Gut, aber warum camelCase?! :)
Leonid Shvechikov

19

Ich schlage vor, das andSchlüsselwort in die zweite Zeile zu verschieben und alle Zeilen mit Bedingungen mit zwei statt vier Leerzeichen einzurücken:

if (cond1 == 'val1' and cond2 == 'val2'
  and cond3 == 'val3' and cond4 == 'val4'):
    do_something

Genau so löse ich dieses Problem in meinem Code. Wenn Sie ein Schlüsselwort als erstes Wort in der Zeile haben, ist die Bedingung viel besser lesbar, und durch Verringern der Anzahl der Leerzeichen wird die Bedingung weiter von der Aktion unterschieden.


9
Ich habe irgendwo in Gries oder Djikstra gelesen, dass es hilfreich ist, den Logikoperator an die Spitze der Zeile zu setzen - um ihn sichtbarer zu machen. Und das mache ich seit den 90ern. Und es hilft.
S.Lott

7
Beachten Sie, dass im Style Guide empfohlen wird, die Bedingung am Ende der Zeile einzufügen.
Harley Holcombe

3
Das stimmt, obwohl ich dem nie zugestimmt habe. Es ist schließlich nur eine Anleitung.
DzinX

8
PEP8 empfiehlt nicht mehr , die Bedingung am Ende der Zeile zu setzen.
Soren Bjornstad

13

Es scheint sich zu lohnen, PEP 0008 (Pythons offizieller Styleguide) zu zitieren , da es dieses Problem in bescheidener Länge kommentiert:

Wenn der bedingte Teil einer ifAnweisung lang genug ist, um das Schreiben über mehrere Zeilen zu erfordern, ist zu beachten, dass die Kombination eines zweistelligen Schlüsselworts (dh if) plus eines einzelnen Leerzeichens plus einer öffnenden Klammer eine natürliche 4- Leerzeichen für die nachfolgenden Zeilen der mehrzeiligen Bedingung. Dies kann zu einem visuellen Konflikt mit der eingerückten Code-Suite ifführen, die in der Anweisung verschachtelt ist und natürlich auch in 4 Leerzeichen eingerückt wird. Dieser PEP nimmt keine explizite Position dazu ein, wie (oder ob) solche bedingten Linien visuell weiter von der verschachtelten Suite innerhalb der ifAnweisung unterschieden werden sollen. Akzeptable Optionen in dieser Situation umfassen, sind aber nicht beschränkt auf:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

Beachten Sie das "nicht beschränkt auf" im obigen Zitat; Neben den im Styleguide vorgeschlagenen Ansätzen sind auch einige der in anderen Antworten auf diese Frage vorgeschlagenen Ansätze akzeptabel.


+1 für PEP8. Dies sollte akzeptiert werden, da es (praktisch) der offizielle Python-Styleguide ist.
Michael - Wo ist Clay Shirky

2
Hervorzuheben ist auch, dass PEP8 seine Haltung ausdrücklich als Folgendes ausdrückt: Dieses PEP nimmt keine explizite Position dazu ein, wie (oder ob) solche bedingten Linien visuell weiter von der verschachtelten Suite innerhalb der if-Anweisung unterschieden werden sollen. Akzeptable Optionen in dieser Situation sind unter anderem: ... (geschnippt) Also, hör auf zu streiten, mach mit etwas, das du magst!
RayLuo

7

Ich mache Folgendes: Denken Sie daran, dass "alle" und "alle" eine Iterierbarkeit akzeptieren. Ich habe also einfach eine lange Bedingung in eine Liste aufgenommen und "alle" die Arbeit machen lassen.

condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']

if all(condition):
   do_something

4

Ich bin überrascht, meine bevorzugte Lösung nicht zu sehen.

if (cond1 == 'val1' and cond2 == 'val2'
    and cond3 == 'val3' and cond4 == 'val4'):
    do_something

Da andes sich um ein Schlüsselwort handelt, wird es von meinem Editor hervorgehoben und unterscheidet sich ausreichend von do_something darunter.


Aber die Fortsetzungslinie unterscheidet sich immer noch nicht von der nächsten logischen Linie ...
Chris Medrela

1
Beachten Sie, dass dies eine PEP 0008-Verletzung ist ( "Der bevorzugte Ort, um einen binären Operator zu umgehen, ist nach dem Operator, nicht davor" ). Ob es Sie interessiert, liegt natürlich bei Ihnen.
Mark Amery

1
Dies ist übrigens nicht mehr meine bevorzugte Lösung. ;)
Marius Gedminas

4

Hinzu kommt, was @krawyoti gesagt hat ... Lange Bedingungen riechen, weil sie schwer zu lesen und schwer zu verstehen sind. Die Verwendung einer Funktion oder einer Variablen macht den Code klarer. In Python bevorzuge ich es, vertikalen Raum zu verwenden, Klammern einzuschließen und die logischen Operatoren am Anfang jeder Zeile zu platzieren, damit die Ausdrücke nicht wie "schwebend" aussehen.

conditions_met = (
    cond1 == 'val1' 
    and cond2 == 'val2' 
    and cond3 == 'val3' 
    and cond4 == 'val4'
    )
if conditions_met:
    do_something

Wenn die Bedingungen wie in einer whileSchleife mehrmals ausgewertet werden müssen , ist die Verwendung einer lokalen Funktion am besten.


1
Darüber hinaus können Sie eine Funktion oder ein Lambda deklarieren, um Ihr wahres Falsch zurückzugeben, anstatt eine zusätzliche Variable zu erstellen.
Techdragon

@Techdragon Wenn die Bedingungen an anderer Stelle liegen sollen, muss der Lambda-Block benannt werden, damit er später in der if-Bedingung referenziert werden kann. Wenn ein Lambda benannt wird, warum dann nicht eine reguläre Funktion? Ich persönlich mag diesen reduzierten booleschen Ausdruck.
Sri Kadimisetty

Ich stimme zu, weshalb ich normalerweise in den meisten Fällen eine Funktion verwenden würde, um sowohl die Lesbarkeit zu verbessern als auch die geistige Verdauung zu erleichtern, wenn ich überfliege, um den Programmsteuerungsfluss zu verstehen. Ich erwähne das Lambda, um sicherzustellen, dass die "kleinere" Option auch für den Fall vorhanden ist, dass Menschen besonders raumbewusst sind.
Techdragon

4

Persönlich mag ich es, langen if-Aussagen Bedeutung zu verleihen. Ich müsste den Code durchsuchen, um ein geeignetes Beispiel zu finden, aber hier ist das erste Beispiel, das mir in den Sinn kommt: Nehmen wir an, ich stoße zufällig auf eine skurrile Logik, bei der ich abhängig von vielen Variablen eine bestimmte Seite anzeigen möchte.

Englisch: "Wenn der angemeldete Benutzer KEIN Administratorlehrer ist, sondern nur ein regulärer Lehrer und selbst kein Schüler ..."

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()

Sicher, das mag gut aussehen, aber das Lesen dieser if-Anweisungen ist eine Menge Arbeit. Wie wäre es, wenn wir die Logik dem Etikett zuweisen, das Sinn macht? Das "Label" ist eigentlich der Variablenname:

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()

Dies mag albern erscheinen, aber Sie haben möglicherweise noch eine andere Bedingung, bei der Sie NUR dann ein anderes Element anzeigen möchten, wenn und nur wenn Sie das Lehrerfenster anzeigen ODER wenn der Benutzer standardmäßig Zugriff auf dieses andere spezifische Feld hat:

if displayTeacherPanel or user.canSeeSpecialPanel():
    showSpecialPanel()

Versuchen Sie, die obige Bedingung zu schreiben, ohne Variablen zum Speichern und Beschriften Ihrer Logik zu verwenden, und Sie erhalten nicht nur eine sehr unordentliche, schwer lesbare logische Anweisung, sondern Sie haben sich auch nur wiederholt. Denken Sie daran, auch wenn es vernünftige Ausnahmen gibt: Wiederholen Sie sich nicht (DRY).


3

"all" und "any" sind nett für die vielen Bedingungen des gleichen Falltyps. ABER sie bewerten immer alle Bedingungen. Wie in diesem Beispiel gezeigt:

def c1():
    print " Executed c1"
    return False
def c2():
    print " Executed c2"
    return False


print "simple and (aborts early!)"
if c1() and c2():
    pass

print

print "all (executes all :( )"
if all((c1(),c2())):
    pass

print

5
Falsch! Sie tun es nur, weil Sie es tun. Versuchen Sie alle (f () für f in [c1, c2]).
Hablabit

2
Ich denke, er hat Funktionen nur als Beispiel verwendet, weil er sie leicht dazu bringen kann, etwas zu drucken. Wenn wir eine Reihe von willkürlichen Ausdrücken in Betracht ziehen, die bis all()dahin in einer Liste enthalten sind f(), werden sie alle ausgewertet , es sei denn, Sie wickeln sie jeweils in ein Lambda ein und verwenden Ihren Trick. Mit anderen Worten, Aaron: Ich denke, Anders hat versucht, über Bedingungen im Allgemeinen zu sprechen, wobei Callables als spezifisches Beispiel verwendet wurden. Ihre Gegenerwiderung gilt jedoch nur für Funktionen.
Brandon Rhodes

3

(Ich habe die Bezeichner leicht geändert, da Namen mit fester Breite nicht für echten Code repräsentativ sind - zumindest nicht für echten Code, auf den ich stoße - und die Lesbarkeit eines Beispiels glauben.)

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4"):
    do_something

Dies funktioniert gut für "und" und "oder" (es ist wichtig, dass sie zuerst in der zweiten Zeile stehen), aber viel weniger für andere lange Bedingungen. Glücklicherweise scheint Ersteres der häufigere Fall zu sein, während Letzteres häufig leicht mit einer temporären Variablen umgeschrieben werden kann. (Es ist normalerweise nicht schwer, aber es kann schwierig oder viel weniger offensichtlich / lesbar sein, den Kurzschluss von "und" / "oder" beim Umschreiben beizubehalten.)

Da ich diese Frage in Ihrem Blogbeitrag zu C ++ gefunden habe , werde ich angeben, dass mein C ++ - Stil identisch ist:

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4") {
    do_something
}

3

Schlicht und einfach, besteht auch pep8-Prüfungen:

if (
    cond1 and
    cond2
):
    print("Hello World!")

In letzter Zeit habe ich die allund any-Funktionen bevorzugt , da ich And and Or-Vergleiche selten mische. Dies funktioniert gut und hat den zusätzlichen Vorteil, dass ich mit dem Verständnis der Generatoren früh versage:

if all([
    cond1,
    cond2,
]):
    print("Hello World!")

Denken Sie daran, eine einzige iterable zu übergeben! Die Übergabe von N-Argumenten ist nicht korrekt.

Hinweis: anyist wie viele orVergleiche, allist wie viele andVergleiche.


Dies lässt sich gut mit dem Verständnis des Generators kombinieren, zum Beispiel:

# Check if every string in a list contains a substring:
my_list = [
    'a substring is like a string', 
    'another substring'
]

if all('substring' in item for item in my_list):
   print("Hello World!")

# or

if all(
    'substring' in item
    for item in my_list
):
    print("Hello World!")

Mehr zum Generatorverständnis


1
Ich sollte auch darauf hinweisen, dass die Bestandskonfiguration von pylint einen Einzug in die Online-Fortsetzung in einem if wünscht; das hat mich davon abgehalten, dieses Schema zu verwenden.
ThorSummoner

2

Was ist, wenn wir nur eine zusätzliche Leerzeile zwischen dem Zustand und dem Körper einfügen und den Rest auf kanonische Weise erledigen?

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):

    do_something

ps Ich benutze immer Tabulatoren, keine Leerzeichen; Ich kann nicht fein einstellen ...


3
Dies wäre sehr verwirrend, besonders wenn der Körper der Bedingung lang ist, denke ich.
Eli Bendersky

Ich stimme Eli zu, die Einkapselung und Einrückung hier ist für lange Schlangen verwirrend. Darüber hinaus ist die neue Regel, dass die Anweisungen andund orin der nächsten Zeile beginnen sollten
virtualxtc

2

Was ich normalerweise mache ist:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something

Auf diese Weise markieren die schließende Klammer und der Doppelpunkt visuell das Ende unseres Zustands.


1
Fast richtig; PEP 8 empfiehlt nun, vor dem andoder zu brechen or.
virtualxtc

2

Alle Befragten, die auch Multi-Bedingungen für die if-Anweisung bereitstellen, sind genauso hässlich wie das vorgestellte Problem. Sie lösen dieses Problem nicht, indem Sie dasselbe tun.

Sogar die Antwort von PEP 0008 ist abstoßend.

Hier ist ein weitaus besser lesbarer Ansatz

condition = random.randint(0, 100) # to demonstrate
anti_conditions = [42, 67, 12]
if condition not in anti_conditions:
    pass

Soll ich meine Worte essen? Überzeugen Sie mich, dass Sie mehrere Bedingungen benötigen, und ich werde diese buchstäblich ausdrucken und zu Ihrer Unterhaltung essen.


Dies ist in der Tat eine sehr nette Art, Multi-Bedingungen zu erfüllen :) Ich weiß nicht, warum es nicht mehr Stimmen gibt :), gibt es irgendwelche Einschränkungen?
dim_user

@SaulCruz gibt es wirklich nicht Nicht nur, dass die Bedingungsvariable nicht wiederholt werden muss, Sie sparen auch die vielen Duplikate der Überprüfung jedes Werts, dies fügt einfach nur die Werte in ein Array ein und lässt die Engine ihren (optimierten) Job erledigen Überprüfen Sie den Zustand für Sie
Stoff

@Stoff Danke, dass du meinen Kommentar entfernt hast. Ich wollte darauf hinweisen, dass Ihr Ansatz die Frage des OP nicht beantwortet. Der von Ihnen angegebene Code kann nicht auf den Code in der Frage angewendet werden. Wenn Sie anders denken, sollten Sie den durch Ihren Ansatz neu formatierten OP-Code hinzufügen, um Ihren Standpunkt zu belegen.
Jeyekomon

Es ist nicht die akzeptierte Antwort, aber es ist eindeutig ein alternativer Ansatz (andere stimmen zu). SO ermutigte alternative Antworten, also was genau ist das Argument? Seien Sie in Ihrer eigenen Frage klar und überlegen Sie vielleicht, Ihre eigene Frage zu öffnen, wenn Sie die richtige Aufmerksamkeit benötigen. Ps Ich bin kein SO Mod, ich kann keine Kommentare entfernen
Stoff

2

Ich denke, die Lösung von @ zkanda wäre gut mit einer kleinen Wendung. Wenn Sie Ihre Bedingungen und Werte in ihren jeweiligen Listen hätten, könnten Sie ein Listenverständnis verwenden, um den Vergleich durchzuführen, was die Dinge für das Hinzufügen von Bedingungs- / Wertepaaren etwas allgemeiner machen würde.

conditions = [1, 2, 3, 4]
values = [1, 2, 3, 4]
if all([c==v for c, v in zip(conditions, values)]):
    # do something

Wenn ich eine solche Aussage fest codieren wollte, würde ich sie aus Gründen der Lesbarkeit folgendermaßen schreiben:

if (condition1==value1) and (condition2==value2) and \
   (condition3==value3) and (condition4==value4):

Und nur um eine andere Lösung mit einem iandBediener herauszubringen :

proceed = True
for c, v in zip(conditions, values):
    proceed &= c==v

if proceed:
    # do something

1
Nur zum Spaß : all(map(eq, have, expected)). (mit from operator import eq)
Gabriel Garcia

1

Nur ein paar andere zufällige Ideen der Vollständigkeit halber. Wenn sie für Sie arbeiten, verwenden Sie sie. Ansonsten ist es wahrscheinlich besser, wenn Sie etwas anderes ausprobieren.

Sie können dies auch mit einem Wörterbuch tun:

>>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> x == y
True

Diese Option ist komplizierter, kann aber auch nützlich sein:

class Klass(object):
    def __init__(self, some_vars):
        #initialize conditions here
    def __nonzero__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                self.cond3 == 'val3' and self.cond4 == 'val4')

foo = Klass()
if foo:
    print "foo is true!"
else:
    print "foo is false!"

Keine Ahnung, ob das für Sie funktioniert, aber es ist eine weitere Option, die Sie in Betracht ziehen sollten. Hier ist noch ein Weg:

class Klass(object):
    def __init__(self):
        #initialize conditions here
    def __eq__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
               self.cond3 == 'val3' and self.cond4 == 'val4')

x = Klass(some_values)
y = Klass(some_other_values)
if x == y:
    print 'x == y'
else:
    print 'x!=y'

Die letzten beiden habe ich nicht getestet, aber die Konzepte sollten ausreichen, um Sie zum Laufen zu bringen, wenn Sie das möchten.

(Und fürs Protokoll: Wenn dies nur eine einmalige Sache ist, ist es wahrscheinlich besser, die Methode zu verwenden, die Sie zuerst vorgestellt haben. Wenn Sie den Vergleich an vielen Stellen durchführen, können diese Methoden die Lesbarkeit ausreichend verbessern, um sie durchzuführen du fühlst dich nicht so schlecht wegen der Tatsache, dass sie irgendwie hackig sind.)


1

Ich habe mich bemüht, auch hier einen vernünftigen Weg zu finden, also bin ich auf eine Idee gekommen (keine Silberkugel, da dies hauptsächlich Geschmackssache ist).

if bool(condition1 and
        condition2 and
        ...
        conditionN):
    foo()
    bar()

Ich finde ein paar Vorteile in dieser Lösung im Vergleich zu anderen, die ich gesehen habe, nämlich, dass Sie genau 4 zusätzliche Einrückungsräume (bool) erhalten, sodass alle Bedingungen vertikal ausgerichtet werden können und der Hauptteil der if-Anweisung eingerückt werden kann ein klarer (ish) Weg. Dies behält auch die Vorteile der Kurzschlussauswertung von Booleschen Operatoren bei, erhöht aber natürlich den Overhead eines Funktionsaufrufs, der im Grunde nichts bewirkt. Sie könnten (gültig) argumentieren, dass jede Funktion, die ihr Argument zurückgibt, hier anstelle von bool verwendet werden könnte, aber wie gesagt, es ist nur eine Idee und letztendlich eine Frage des Geschmacks.

Komischerweise kam mir beim Schreiben und Nachdenken über das "Problem" eine weitere Idee, mit der der Aufwand für einen Funktionsaufruf entfällt. Warum nicht angeben, dass wir mit zusätzlichen Klammerpaaren in eine komplexe Bedingung eintreten werden? Sagen Sie 2 weitere, um einen schönen 2-Leerzeichen-Einzug der Unterbedingungen relativ zum Hauptteil der if-Anweisung zu erhalten. Beispiel:

if (((foo and
      bar and
      frob and
      ninja_bear))):
    do_stuff()

Ich mag das irgendwie, denn wenn du es dir ansiehst, läutet sofort eine Glocke in deinem Kopf und sagt: "Hey, hier ist eine komplexe Sache los!" . Ja, ich weiß, dass Klammern die Lesbarkeit nicht verbessern, aber diese Bedingungen sollten selten genug auftreten. Wenn sie angezeigt werden, müssen Sie sie trotzdem vorsichtig lesen (weil sie komplex sind ).

Wie auch immer, nur zwei weitere Vorschläge, die ich hier nicht gesehen habe. Hoffe das hilft jemandem :)


1

Sie können es in zwei Zeilen aufteilen

total = cond1 == 'val' and cond2 == 'val2' and cond3 == 'val3' and cond4 == val4
if total:
    do_something()

Oder fügen Sie sogar jeweils eine Bedingung hinzu. Auf diese Weise trennt es zumindest die Unordnung von der if.


1

Ich weiß, dass dieser Thread alt ist, aber ich habe Python 2.7-Code und PyCharm (4.5) beschwert sich immer noch über diesen Fall:

if foo is not None:
    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            # some comment about do_something
            do_something

Selbst mit der PEP8-Warnung "visuell eingerückte Zeile mit demselben Einzug wie die nächste logische Zeile" ist der tatsächliche Code vollständig in Ordnung? Es ist nicht "Einrückung?"

... es gibt Zeiten, in denen ich mir wünschte, Python hätte die Kugel gebissen und wäre nur mit geschweiften Klammern gegangen. Ich frage mich, wie viele Fehler im Laufe der Jahre aufgrund versehentlicher falscher Einrückungen versehentlich eingeführt wurden ...


0

Packen Sie Ihre Bedingungen in eine Liste und machen Sie dann etwas. mögen:

if False not in Conditions:
    do_something

0

Ich finde, wenn ich lange Bedingungen habe, habe ich oft einen kurzen Code-Körper. In diesem Fall rücke ich den Körper nur doppelt ein, also:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):
        do_something

1
@qarma, möchtest du erweitern? Es ist sicherlich besser als die Verwendung von
Zeilenfortsetzungszeichen

Dies ist in der Tat ein gültiger Fall für die Fortsetzung der Leitung. IMPO-Klammern kennzeichnen ein Tupel oder einen Funktionsaufruf. Die Verwendung von OP ist sehr C-ähnlich. Ich bevorzuge nach Möglichkeit die Python-Syntax. Ich gebe zu, dass \ jedoch nicht allgemein bevorzugt wird.
Dima Tisnek

0
  if cond1 == 'val1' and \
     cond2 == 'val2' and \
     cond3 == 'val3' and \
     cond4 == 'val4':
      do_something

oder wenn dies klarer ist:

  if cond1 == 'val1'\
     and cond2 == 'val2'\
     and cond3 == 'val3'\
     and cond4 == 'val4':
      do_something

Es gibt keinen Grund, warum der Einzug in diesem Fall ein Vielfaches von 4 sein sollte, z. B. "Ausgerichtet am öffnenden Trennzeichen":

http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Indentation#Indentation


Der Google-Leitfaden enthält auch ein Beispiel für eine komplexe Bedingung , die dem vom OP erwähnten „naheliegendsten Weg, dies zu tun“ entspricht. Obwohl das Handbuch nicht ausdrücklich die Formatierung langer "Wenn" befürwortet.
Anton Strogonoff

0

Hier ist ein anderer Ansatz:

cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
if all([eval(i) for i in cond_list]):
 do something

Dies macht es auch einfach, eine weitere Bedingung hinzuzufügen, ohne die if-Anweisung zu ändern, indem einfach eine andere Bedingung an die Liste angehängt wird:

cond_list.append('cond5=="val5"')

0

Ich benutze normalerweise:

if ((cond1 == 'val1' and cond2 == 'val2' and
     cond3 == 'val3' and cond4 == 'val4')):
    do_something()

0

Wenn unsere if & an else-Bedingung mehrere Anweisungen ausführen muss, können wir wie unten schreiben. Jedes Mal, wenn wir ein anderes Beispiel mit einer Aussage darin haben.

Danke, es funktioniert für mich.

#!/usr/bin/python
import sys
numberOfArgument =len(sys.argv)
weblogic_username =''
weblogic_password = ''
weblogic_admin_server_host =''
weblogic_admin_server_port =''


if numberOfArgument == 5:
        weblogic_username = sys.argv[1]
        weblogic_password = sys.argv[2]
        weblogic_admin_server_host =sys.argv[3]
        weblogic_admin_server_port=sys.argv[4]
elif numberOfArgument <5:
        print " weblogic UserName, weblogic Password and weblogic host details are Mandatory like, defalutUser, passwordForDefaultUser, t3s://server.domainname:7001 ."
        weblogic_username = raw_input("Enter Weblogic user Name")
        weblogic_password = raw_input('Enter Weblogic user Password')
        weblogic_admin_server_host = raw_input('Enter Weblogic admin host ')
        weblogic_admin_server_port = raw_input('Enter Weblogic admin port')
#enfelif
#endIf

0

Verzeihen Sie meine Noobness, aber es kommt vor, dass ich #Python nicht so gut kenne wie jeder von Ihnen hier, aber es kommt vor, dass ich etwas Ähnliches gefunden habe, als ich meine eigenen Objekte in einer 3D-BIM-Modellierung geschrieben habe, also werde ich meinen Algorithmus anpassen das von Python.

Das Problem, das ich hier finde, ist doppelseitig:

  1. Meine Werte scheinen für jemanden fremd zu sein, der versucht, das Skript zu entschlüsseln.
  2. Die Codewartung ist mit hohen Kosten verbunden, wenn diese Werte geändert werden (höchstwahrscheinlich) oder wenn neue Bedingungen hinzugefügt werden müssen (fehlerhaftes Schema).

Um all diese Probleme zu umgehen, muss Ihr Skript so aussehen

param_Val01 = Value 01   #give a meaningful name for param_Val(i) preferable an integer
param_Val02 = Value 02
param_Val03 = Value 03
param_Val04 = Value 04   # and ... etc

conditions = 0           # this is a value placeholder

########
Add script that if true will make:

conditions = conditions + param_Val01   #value of placeholder is updated
########

### repeat as needed


if conditions = param_Val01 + param_Val02 + param_Val03 + param_Val04:
    do something

Vorteile dieser Methode:

  1. Skript ist lesbar.

  2. Das Skript kann einfach gepflegt werden.

  3. Bedingungen ist eine 1-Vergleichsoperation mit einer Summe von Werten, die die gewünschten Bedingungen darstellt.
  4. Keine Notwendigkeit für mehrstufige Bedingungen

Hoffe es hilft euch allen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.