Stylizować warunki wieloliniowe w instrukcjach „jeśli” [Zamknięte]


676

Czasami łamię długie warunki ifws na kilku liniach. Najbardziej oczywistym sposobem na to jest:

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

Nie jest bardzo atrakcyjny wizualnie, ponieważ akcja miesza się z warunkami. Jest to jednak naturalny sposób przy użyciu prawidłowego wcięcia w Pythonie 4 spacji.

W tej chwili używam:

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

Ale to nie jest bardzo ładne. :-)

Czy możesz polecić alternatywny sposób?


2
Jeśli Twój edytor używa pakietu pep8 Python do wykrywania ostrzeżeń o naruszeniach PEP8 , musisz albo wyłączyć błąd E125, albo znaleźć rozwiązanie formatujące, które spełnia pep8kryteria pakietu. W pep8pakiet za problem # 126 jest o ustalenie pakiet ściśle przestrzegać spec PEP8. Dyskusja na ten temat zawiera również sugestie dotyczące stylu, które można zobaczyć tutaj.
akaihola

1
Zauważ, że w pierwszym przykładzie pep8 wyrzuci „E129 wizualnie wciętą linię z takim samym wcięciem jak następna logiczna linia”.
Taylor Edmiston,

To pytanie jest bardzo stare i ma mnóstwo poglądów, ale jest jednoznacznie oparte na opiniach. Język „nie jest zbyt atrakcyjny” i „nie jest bardzo ładny” określa kryteria, które rzekomo poprawna odpowiedź to ta, która najlepiej odpowiada preferencjom estetycznym pytających (tj. Opinii). Mógłbym zadać dokładnie to samo pytanie i twierdzić, że nie jest to duplikat, ponieważ mój gust estetyczny kwalifikuje go jako inny i doprowadzi do innej „właściwej” odpowiedzi.
Z4-poziom

@ Z4-tier: tak, opiera się na opiniach. Ale zapytano go 12 lat temu. SO było wtedy innym, milszym miejscem. Ostatnio narasta liczba ocen negatywnych, ponieważ zmieniły się standardy SO. Mimo to, po obejrzeniu> 1 miliona razy, mam nadzieję, że przynosi więcej korzyści niż szkód na świecie. Z pewnością widzę, jak ludzie zastanawiają się dziś nad tym samym pytaniem, przeglądają go, lądują w tej dyskusji i uważają, że przydatne jest skalibrowanie ich myślenia. Do wyboru jest kilka wysoko głosowanych odpowiedzi.
Eli Bendersky

@EliBendersky całkowicie się zgadza. To tak, jakby SO przeżywa trwający kryzys tożsamości: chociaż wyraźnie nie pasuje do „zasad” (liczba prawidłowych odpowiedzi jest tego dowodem), jest równie jasne, że wnosi wartość dodaną. Wszystkie rzeczy są jednakowe, wolałbym raczej pracować z kimś, kto opracował wyrażalne i uzasadnione poglądy na styl kodowania, nawet jeśli ich poglądy różnią się od moich.
Z4-poziom

Odpowiedzi:


749

Nie musisz używać 4 spacji w drugiej linii warunkowej. Może użyć:

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

Nie zapominaj też, że biała spacja jest bardziej elastyczna niż myślisz:

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

Oba są jednak dość brzydkie.

Może stracisz nawiasy kwadratowe (jednak Przewodnik po stylu odradza to)?

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

To przynajmniej daje pewne rozróżnienie.

Lub nawet:

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

Myślę, że wolę:

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

Oto przewodnik po stylach , który (od 2010 r.) Zaleca stosowanie nawiasów.


45
Zauważ, że końcowe \ rozwiązania nie są zalecane przez PEP 8. Jednym z powodów jest to, że jeśli spacja zostanie dodana przez pomyłkę po \, może nie zostać wyświetlona w edytorze, a kod staje się niepoprawny pod względem składniowym.
Eric O Lebigot,

14
Jest to błędne, przewodnik po stylu mówi: „Długie linie mogą być dzielone na wiele linii przez zawijanie wyrażeń w nawiasach. Powinny być one stosowane zamiast ciągłego odwrotnego ukośnika”. Możesz to zobaczyć tutaj: python.org/dev/peps/pep-0008/#maximum-line-length
joshcartme

8
@joshcartme PEP zmienił się na hg.python.org/peps/rev/7a48207aaab6, aby wyraźnie zniechęcić odwrotne ukośniki. Zaktualizuję odpowiedź.
Harley Holcombe

3
Dzięki, prawdopodobnie dobrym pomysłem jest również zaktualizowanie przykładów, ponieważ nie są one teraz zalecane. Próbowałem to rozgryźć sam i byłem zdezorientowany rozbieżnością między twoją odpowiedzią a przewodnikiem po stylu (stąd mój komentarz). Nie tylko starałem się być pedantyczny.
joshcartme

3
PEP 8 odradza teraz łamanie po andi if.
virtualxtc

124

W zdegenerowanym przypadku uciekłem się do następujących przypadków, w których są to po prostu AND lub OR.

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

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

Goli kilka znaków i wyjaśnia, że ​​warunek nie jest subtelny.


4
To ciekawe podejście. Nie rozwiązuje jednak problemu długich warunków
Eli Bendersky

20
Jest ok, jeśli nie obchodzi Cię zwarcie.
Constantin,

63
shortcirtuiting nie zawsze dotyczy szybkiego. Chociaż nie jest dobre praktyki kodowania może być istniejący kod tak: if destroy_world and DestroyTheWorld() == world_is_destroyed: .... Świetnie, teraz właśnie przypadkiem zniszczyłeś świat. JAK MOGŁEŚ?
Aaron

4
Dziwi mnie, że ma tak wiele pozytywnych opinii. Ta odpowiedź całkowicie ignoruje pierwotne pytanie dotyczące stylizacji wielowierszowych instrukcji warunkowych.
Przemek D

2
To wyrażenie nie jest leniwe. Więc to nie jest równoważne, jeśli przestrzegane są niektóre warunki ochrony, a może jeden z nich nie spełnia.
jasny eugen

57

Ktoś musi tutaj poprzeć pionowe białe znaki! :)

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

Dzięki temu każdy warunek jest wyraźnie widoczny. Pozwala także na czystsze wyrażanie bardziej złożonych warunków:

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

Tak, dla przejrzystości wymieniamy trochę pionowych nieruchomości. Warto IMO.


19
To nie wydaje się być piękne ani zgodne z PEP8. PEP8 mówi, że preferowanym miejscem do złamania wokół operatorem binarnym (np andjak również or) jest po operatora, a nie przed nim.
Chris Medrela,

7
@ChristopherMedrela, czy to uzasadnia? myślę, że umieszczenie podziału linii przed operatorem logicznym jest o wiele wyraźniejsze
Norill Tempest

4
Stawianie opreratora na pierwszym miejscu jest dość powszechne w świecie węzłów. Uzasadnieniem jest to, że zauważamy i czytamy rzeczy po lewej stronie znacznie szybciej niż rzeczy po prawej - przynajmniej w kulturach zachodnich. Bardzo poprawny w JavaScript, gdzie zapomniany przecinek może powodować ciche błędy.
tomekwi

11
Nie rób tego proszę. Nie tylko nie jest to, PEP8ale utrudnia określenie operacji logicznej, którą łączysz. Zrobiłbym to, gdyby przyszedł do mojego biurka poprzez przegląd kodu.
Urda

11
W obecnej wersji PEP8 przerwanie przed operatorem binarnym lub po nim jest uważane za dopuszczalne , a przed operatorem za lepsze dla nowego kodu.
Soren Bjornstad,

31

Wolę ten styl, gdy mam strasznie duży warunek if:

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

2
+1 za przechowywanie wcięć, w których możesz je śledzić. Lubię pytona i często go używam, ale ciągle jestem zirytowany tym, że zmuszony jestem do wcięcia. Multi-linia, jeśli naprawdę niszczy estetykę, nawet jeśli jest dobrze wykonana.
mightypile 22.12.13

4
Zauważ, że umieszczenie twojego andi oroperatorów na początku linii narusza PEP 0008 , który stwierdza: „Preferowanym miejscem na obejście operatora binarnego jest po nim, a nie przed nim”. . Lubię jednak klamrę zamykającą i dwukropek na ich własnej linii, aby oddzielić warunek if od ciała (i jest to całkowicie możliwe, zachowując operatorów boolowskich na końcu linii dla zgodności z PEP-0008).
Mark Amery

8
od 2016 r .: 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.(stylem Knutha jest rozpoczęcie linii od operatora).
cowbert

27

Oto moje bardzo osobiste podejście: długie warunki są (moim zdaniem) zapachem kodu, który sugeruje refaktoryzację do funkcji / metody zwracającej wartość logiczną. Na przykład:

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

Teraz, gdybym znalazł sposób na poprawienie warunków na wielu liniach, prawdopodobnie zadowoliłbym się ich posiadaniem i pominąłbym refaktoryzację.

Z drugiej strony, ich zakłócenie mój zmysł estetyczny stanowi zachętę do refaktoryzacji.

W związku z tym doszedłem do wniosku, że warunki na wielu liniach powinny wyglądać brzydko i jest to zachęta do ich unikania.


23

To nie poprawia się tak bardzo, ale ...

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

if allCondsAreOK:
   do_something

1
Ciekawa alternatywa. Ale 2 dodatkowe wiersze :-)
Eli Bendersky,

Naprawdę nie działałby tak dobrze w pętli iteracyjnej, nie działałby z funkcjami, które coś robią ... i mówiąc szczerze - brzydko
Mez

9
Brian, częściowo się nie zgadzam. Używanie zmiennych do pośrednich wyników obliczeń może ułatwić zrozumienie kodu, aw skompilowanym języku nie będzie miało żadnego wpływu na wydajność. Prawdopodobnie zadziałałoby w Pythonie, choć w ogóle nie używałbym Pythona, jeśli wydajność była tak ważna.
Mark Baker,

1
@ MarkBaker Zgadzałem się z tym, co napisałeś, dopóki nie przeczytałem Martina Fowlersa „Refaktoryzacja”. Zapewnia doskonały argument, że takie zmienne pośrednie powodują więcej szkody niż korzyści. Hamują późniejsze refaktoryzowanie. Rezygnacja z nich prowadzi do bardziej funkcjonalnego stylu programowania, który dobrze nadaje się do refaktoryzacji. Zaskoczyło mnie to, ale uważam, że ma rację i od tego czasu starałem się wyeliminować z mojego kodu niepotrzebne półprodukty - nawet jeśli są używane więcej niż jeden raz.
Jonathan Hartley

2
Dobrze, ale dlaczego camelCase ?! :)
Leonid Shvechikov,

19

Sugeruję przeniesienie andsłowa kluczowego do drugiej linii i wcięcie wszystkich linii zawierających warunki dwoma spacjami zamiast czterech:

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

Właśnie tak rozwiązuję ten problem w moim kodzie. Posiadanie słowa kluczowego jako pierwszego słowa w wierszu sprawia, że ​​warunek jest znacznie bardziej czytelny, a zmniejszenie liczby spacji dodatkowo odróżnia warunek od działania.


9
Czytałem gdzieś w Gries lub Djikstrze, że umieszczenie operatora logiki z przodu linii - czyniąc go bardziej widocznym - pomogło. Robię to od lat 90-tych. I to pomaga.
S.Lott,

7
Zauważ, że Przewodnik po stylu zaleca umieszczenie warunkowe na końcu linii.
Harley Holcombe,

3
To prawda, chociaż nigdy się z tym nie zgodziłem. W końcu to tylko przewodnik.
DzinX,

8
PEP8 nie zaleca już umieszczania warunku na końcu linii.
Soren Bjornstad,

14

Wydaje się, że warto zacytować PEP 0008 (oficjalny przewodnik po stylu Pythona), ponieważ skromnie komentuje to zagadnienie:

Gdy część warunkowa if-statement jest wystarczająco długa, aby wymagać, aby była napisana w wielu wierszach, warto zauważyć, że połączenie dwuliterowego słowa kluczowego (tj. if), Pojedynczej spacji oraz otwierającego nawiasu tworzy naturalny 4- wcięcie spacji dla kolejnych linii warunku wielowierszowego. Może to powodować konflikt wizualny z wciętym pakietem kodu zagnieżdżonym w if-statement, który również byłby naturalnie wcięty do 4 spacji. Ten PEP nie zajmuje jednoznacznego stanowiska co do tego, jak (lub czy) dodatkowo wizualnie odróżnić takie linie warunkowe od zestawu zagnieżdżonego w if-statement. Dopuszczalne opcje w tej sytuacji obejmują między innymi:

# 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()

Zwróć uwagę na „nieograniczony do” w powyższym cytacie; oprócz podejść sugerowanych w przewodniku po stylu, niektóre z sugerowanych w innych odpowiedziach na to pytanie są również dopuszczalne.


+1 dla PEP8. To powinno być akceptowane, ponieważ jest (praktycznie) oficjalny podręcznik stylu Pythona.
Michael - Where's Clay Shirky

2
Warto również podkreślić, że PEP8 wyraźnie określa swoje stanowisko, ponieważ PEP nie zajmuje wyraźnego stanowiska, w jaki sposób (lub czy), aby dalej wizualnie odróżniać takie linie warunkowe od zestawu zagnieżdżonego w instrukcji if -statement. Akceptowalne opcje w tej sytuacji obejmują między innymi: ... (przycięte) Więc przestań się kłócić, idź z czymś, co lubisz!
RayLuo

7

Oto, co robię, pamiętaj, że „wszystko” i „każdy” akceptuje iterowalność, więc po prostu umieszczam długi warunek na liście i pozwalam „wszystkim” wykonać pracę.

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

if all(condition):
   do_something

4

Jestem zaskoczony, że nie widzę mojego preferowanego rozwiązania,

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

Ponieważ andjest to słowo kluczowe, zostaje ono wyróżnione przez mój edytor i wygląda wystarczająco inaczej niż do_something poniżej.


Ale linia kontynuacji nadal nie odróżnia się od następnej linii logicznej ...
Chris Medrela,

1
Zauważ, że jest to naruszenie PEP 0008 ( „Preferowanym miejscem na obejście operatora binarnego jest po nim, a nie przed nim” ). To, czy ci zależy, oczywiście zależy od ciebie.
Mark Amery

1
Nawiasem mówiąc, nie jest to już moje preferowane rozwiązanie. ;)
Marius Gedminas

4

Dodając do tego, co powiedział @krawyoti ... Długie warunki pachną, ponieważ są trudne do odczytania i trudne do zrozumienia. Użycie funkcji lub zmiennej sprawia, że ​​kod jest wyraźniejszy. W Pythonie wolę używać spacji pionowej, otaczać nawiasy i umieszczać operatory logiczne na początku każdej linii, aby wyrażenia nie wyglądały jak „swobodne”.

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

Jeśli warunki wymagają oceny więcej niż raz, jak w whilepętli, najlepiej jest użyć funkcji lokalnej.


1
Oprócz tego możesz zadeklarować funkcję lub lambda, aby zwróciły twój prawdziwy fałsz, w przeciwieństwie do tworzenia dodatkowej zmiennej.
Techdragon,

@Techdragon, jeśli warunki mają być gdzie indziej, to umieszczenie ich w bloku lambda wymaga nazwy bloku lambda, aby można było do niego odwoływać się później w warunku if. Jeśli ma zostać nazwana lambda, dlaczego w ogóle nie jest to zwykła funkcja? Osobiście podoba mi się to zredukowane wyrażenie boolowskie.
Sri Kadimisetty,

Zgadzam się, dlatego zwykle używałbym funkcji w większości przypadków, zarówno w celu poprawy czytelności, jak i łatwości trawienia umysłowego podczas przeglądania, aby zrozumieć przebieg sterowania programem. Wspominam o lambdzie, aby upewnić się, że opcja „mniejsza” jest również dostępna w przypadku, gdy ludzie są szczególnie świadomi przestrzeni.
Techdragon 13.09.2013

4

Osobiście lubię dodawać znaczenie do długich instrukcji if. Musiałbym przeszukać kod, aby znaleźć odpowiedni przykład, ale oto pierwszy przykład, który przychodzi mi na myśl: powiedzmy, że wpadłem na dziwaczną logikę, w której chcę wyświetlić określoną stronę w zależności od wielu zmiennych.

Angielski: „Jeśli zalogowany użytkownik NIE jest nauczycielem-administratorem, ale jest zwykłym nauczycielem i sam nie jest uczniem…”

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

Pewnie może to wyglądać dobrze, ale czytanie ich, jeśli stwierdzenia to dużo pracy. A może przypiszemy logikę do etykiety, która ma sens. „Etykieta” jest w rzeczywistości nazwą zmiennej:

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

Może się to wydawać głupie, ale możesz mieć jeszcze jeden warunek, w którym TYLKO chcesz wyświetlić inny element tylko wtedy i tylko wtedy, gdy wyświetlasz panel nauczyciela LUB jeśli użytkownik ma domyślnie dostęp do tego innego określonego panelu:

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

Spróbuj napisać powyższy warunek bez użycia zmiennych do przechowywania i etykietowania swojej logiki, i nie tylko otrzymujesz bardzo niechlujne, trudne do odczytania zdanie logiczne, ale po prostu powtórzyłeś się. Chociaż istnieją uzasadnione wyjątki, pamiętaj: Don't Repeat Yourself (DRY).


3

„all” i „any” są dobre dla wielu warunków tego samego typu. ALE zawsze oceniają wszystkie warunki. Jak pokazano w tym przykładzie:

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
Błędny! Robią to tylko dlatego , że ty . Wypróbuj wszystkie (f () dla f w [c1, c2]).
habnabit

2
Myślę, że używał funkcji tylko jako przykładu, ponieważ może łatwo zmusić je do wydrukowania czegoś. Jeśli weźmiemy pod uwagę serię dowolnych wyrażeń podanych na liście all(), chyba że zamierzasz zawinąć je w lambda i użyć swojej f()sztuczki, wszystkie zostaną ocenione. Innymi słowy, Aaron: Myślę, że Anders starał się mówić ogólnie o warunkach, wykorzystując kallaby jako konkretny przykład; ale duplika dotyczy tylko funkcji.
Brandon Rhodes,

3

(Lekko zmodyfikowałem identyfikatory, ponieważ nazwy o stałej szerokości nie są reprezentatywne dla prawdziwego kodu - przynajmniej nie prawdziwego kodu, z którym się spotykam - i uwierzę w czytelność przykładu).

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

Działa to dobrze w przypadku „i” i „lub” (ważne, aby były pierwsze w drugiej linii), ale znacznie mniej w przypadku innych długich warunków. Na szczęście te pierwsze wydają się być bardziej powszechnym przypadkiem, podczas gdy te drugie często można łatwo przepisać za pomocą zmiennej tymczasowej. (Zazwyczaj nie jest to trudne, ale może być trudne lub znacznie mniej oczywiste / czytelne, aby zachować zwarcie „i” / „lub” podczas przepisywania.)

Ponieważ znalazłem to pytanie w Twoim blogu na temat C ++ , dodam , że mój styl C ++ jest identyczny:

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

3

Prosty i prosty, również przechodzi testy pep8:

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

W ostatnim czasie wolałem funkcje alli any, ponieważ rzadko mieszam porównania And i Or, działa to dobrze i ma dodatkową zaletę: wczesne niepowodzenie ze zrozumieniem generatorów:

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

Pamiętaj tylko, aby przekazać jedną iterację! Przekazywanie N-argumentów jest nieprawidłowe.

Uwaga: anyjest jak wiele orporównań, alljest jak wiele andporównań.


To ładnie łączy się ze zrozumieniem generatora, na przykład:

# 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!")

Więcej na: zrozumienie generatora


1
Powinienem również wskazać, że konfiguracja zapasów pylinta wymaga kontynuacji linii w kontynuacji w if; co zniechęciło mnie do korzystania z tego schematu.
ThorSummoner,

2

Co jeśli wstawimy tylko dodatkową pustą linię między stanem a ciałem, a resztę wykonamy w sposób kanoniczny?

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

    do_something

ps Zawsze używam tabulatorów, a nie spacji; Nie mogę dostroić ...


3
Myślę, że byłoby to bardzo mylące, zwłaszcza gdy ciało warunkowe jest długie.
Eli Bendersky,

Zgadzam się z Heli, tutaj enkapsulacja i wcięcie jest mylące dla długich linii. Co więcej, nowa zasada mówi, że instrukcje andi orpowinny zaczynać się w następnym wierszu
virtualxtc

2

Zwykle robię to:

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

w ten sposób klamra zamykająca i dwukropek wizualnie oznaczają koniec naszego stanu.


1
Prawie poprawne; PEP 8 zaleca teraz łamanie przed andlub or.
virtualxtc

2

Wszyscy respondenci, którzy udostępniają również wiele warunków warunkowych dla instrukcji if, są tak samo brzydkie, jak przedstawiony problem. Nie rozwiązujesz tego problemu, robiąc to samo…

Nawet odpowiedź PEP 0008 jest odpychająca.

Oto znacznie bardziej czytelne podejście

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

Chcesz, żebym zjadł moje słowa? Przekonaj mnie, że potrzebujesz wielu warunków, a ja dosłownie wydrukuję to i zjem to dla twojej rozrywki.


to jest naprawdę bardzo fajny sposób na robienie wielu warunków warunkowych :) nie wiem, dlaczego nie ma więcej głosów :), czy są jakieś zastrzeżenia?
dim_user

@ SaulCruz naprawdę tam nie ma Nie tylko zmienna warunku nie musi być powtarzana, ale także oszczędzasz na wielu duplikatach sprawdzania każdej wartości, to po prostu umieszcza tylko wartości w tablicy i pozwala silnikowi wykonać (zoptymalizowane) zadanie w sprawdzam twój stan
Stoff

@Stoff Dziękujemy za usunięcie mojego komentarza. Chciałem zaznaczyć, że twoje podejście nie odpowiada na pytanie PO. Podany kod nie może być zastosowany do kodu w pytaniu. Jeśli uważasz inaczej, powinieneś dodać kod OP przeformatowany przez twoje podejście, aby udowodnić swoją rację.
Jeyekomon

Nie jest to akceptowana odpowiedź, jednak jest to oczywiście podejście alternatywne (inni się zgadzają). TAK zachęcałem do alternatywnych odpowiedzi, więc jaki jest dokładnie argument? Wyraźnie określ swoje własne pytanie, być może rozważ otwarcie pytania, jeśli potrzebujesz odpowiedniej uwagi. Ps Nie jestem modem SO, nie mogę usunąć komentarzy
Stoff

2

Myślę, że rozwiązanie @ zkanda byłoby dobre z niewielkim zwrotem akcji. Jeśli posiadasz swoje warunki i wartości na ich własnych listach, możesz użyć porównania list, aby dokonać porównania, co uczyniłoby sprawę nieco bardziej ogólną dla dodawania par warunek / wartość.

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

Gdybym chciał zakodować takie zdanie w taki sposób, napisałbym to w taki sposób, aby zapewnić czytelność:

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

I po prostu rzucić inne rozwiązanie z iandoperatorem :

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

if proceed:
    # do something

1
Tak dla zabawy: all(map(eq, have, expected)). (z from operator import eq)
Gabriel Garcia

1

Kilka innych przypadkowych pomysłów dla kompletności. Jeśli działają dla Ciebie, użyj ich. W przeciwnym razie prawdopodobnie lepiej będzie spróbować czegoś innego.

Możesz to również zrobić za pomocą słownika:

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

Ta opcja jest bardziej skomplikowana, ale może się również przydać:

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!"

Nie wiem, czy to działa dla Ciebie, ale jest to kolejna opcja do rozważenia. Oto jeszcze jeden sposób:

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'

Dwa ostatnie, których nie testowałem, ale koncepcje powinny wystarczyć, aby zacząć, jeśli z tym chcesz.

(A dla przypomnienia, jeśli jest to jednorazowa sprawa, prawdopodobnie lepiej będzie skorzystać z metody przedstawionej na początku. Jeśli porównujesz w wielu miejscach, metody te mogą zwiększyć czytelność na tyle, aby nie czujesz się tak źle z powodu faktu, że są trochę hacky).


1

Walczyłem też o znalezienie przyzwoitego sposobu, aby to zrobić, więc właśnie wpadłem na pomysł (nie srebrną kulę, ponieważ jest to głównie kwestia gustu).

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

Znalazłem kilka zalet tego rozwiązania w porównaniu do innych, które widziałem, a mianowicie otrzymujesz dokładnie 4 dodatkowe wcięcia (bool), pozwalając na wyrównanie wszystkich warunków w pionie, a treść instrukcji if można wciąć w jasny (ish) sposób. Zachowuje to również zalety oceny zwarcia operatorów logicznych, ale oczywiście dodaje narzut wywołania funkcji, która w zasadzie nic nie robi. Można argumentować (słusznie), że każda funkcja zwracająca swój argument może być tutaj użyta zamiast bool, ale jak powiedziałem, to tylko pomysł i ostatecznie kwestia gustu.

Zabawne, kiedy to pisałem i myślałem o „problemie”, wpadłem na jeszcze jeden pomysł, który usuwa narzut wywołania funkcji. Dlaczego nie wskazać, że za chwilę wejdziemy w złożony stan, używając dodatkowych par nawiasów? Powiedz jeszcze 2, aby uzyskać ładne wcięcie o 2 spacje warunków podrzędnych względem treści instrukcji if. Przykład:

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

Podoba mi się to, ponieważ kiedy na to patrzysz, natychmiast dzwoni ci w głowie dzwonek: „hej, dzieje się tu coś skomplikowanego! . Tak, wiem, że nawiasy nie poprawiają czytelności, ale warunki te powinny pojawiać się rzadko, a kiedy się pojawią, i tak będziesz musiał je zatrzymać i uważnie przeczytać (ponieważ są złożone ).

Tak czy inaczej, jeszcze dwie propozycje, których tu nie widziałem. Mam nadzieję, że to komuś pomoże :)


1

Możesz podzielić go na dwie linie

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

Lub nawet dodaj jeden warunek na raz. W ten sposób przynajmniej oddziela bałagan od if.


1

Wiem, że ten wątek jest stary, ale mam trochę kodu Python 2.7 i PyCharm (4.5) wciąż narzeka na ten przypadek:

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

Nawet jeśli ostrzeżenie PEP8 „wizualnie wcięty wiersz z takim samym wcięciem jak następny wiersz logiczny”, rzeczywisty kod jest całkowicie OK? To nie jest „nadmierne wcięcie?”

... są chwile, w których chciałbym, żeby Python ugryzł kulę i po prostu poszedł z kręconymi klamrami. Zastanawiam się, ile błędów wprowadzono przypadkowo na przestrzeni lat z powodu przypadkowego błędnego wcięcia ...


0

Spakuj swoje warunki do listy, a potem zrób coś. lubić:

if False not in Conditions:
    do_something

0

Uważam, że gdy mam długie warunki, często mam krótki kod. W takim przypadku po prostu podwójnie wcięłem ciało, a zatem:

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

1
@qarma, czy chciałbyś się rozwinąć? Jest to z pewnością lepsze niż używanie znaków kontynuacji linii, które są zalecane przez PEP 8
xorsyst

Jest to w rzeczywistości uzasadniony przypadek kontynuacji linii. IMPO Nawiasy oznaczają krotkę lub wywołanie funkcji. Zastosowanie OP jest bardzo podobne do C, w miarę możliwości wolę składnię Pythona. Przyznaję, że \ nie jest powszechnie uprzywilejowana.
Dima Tisnek

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

lub jeśli jest to jaśniejsze:

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

W tym przypadku nie ma powodu, dla którego wcięcie powinno być wielokrotnością liczby 4, np. Patrz „Wyrównany z ogranicznikiem otwarcia”:

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


Przewodnik Google zawiera również przykład złożonego warunku , który pasuje do „najbardziej oczywistego sposobu na zrobienie tego”, jak wspomniano w PO. Chociaż przewodnik nie zaleca jednoznacznego formatowania długich „jeśli” w ten sposób.
Anton Strogonoff

0

Oto inne podejście:

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

Ułatwia to także łatwe dodanie kolejnego warunku bez zmiany instrukcji if, po prostu dodając inny warunek do listy:

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

0

Zwykle używam:

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

0

jeśli nasz warunek if & else musi wykonać w nim wiele instrukcji, możemy napisać jak poniżej. Za każdym razem, gdy mamy przykład z jednym stwierdzeniem w środku.

Dzięki, to działa dla mnie.

#!/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

Przepraszam, moja noobness, ale zdarza się, że nie jestem tak dobrze zaznajomiony z #Python, jak ktokolwiek z was tutaj, ale zdarza się, że znalazłem coś podobnego podczas pisania własnych obiektów w modelowaniu 3D BIM, więc dostosuję mój algorytm do python.

Problem, który tu znajduję, jest dwustronny:

  1. Wartości wydają mi się obce dla kogoś, kto może spróbować odczytać skrypt.
  2. Utrzymanie kodu będzie kosztowne, jeśli te wartości zostaną zmienione (najbardziej prawdopodobne) lub jeśli konieczne będzie dodanie nowych warunków (uszkodzony schemat)

Aby ominąć wszystkie te problemy, skrypt musi działać w ten sposób

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

Zalety tej metody:

  1. Skrypt jest czytelny.

  2. Skrypt można łatwo utrzymać.

  3. warunki to operacja porównania 1 z sumą wartości reprezentujących pożądane warunki.
  4. Nie potrzeba warunków wielopoziomowych

Mam nadzieję, że pomoże wam wszystkim

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.