Wielu programistów Pythona prawdopodobnie nie zdaje sobie sprawy, że składnia while
pętli i for
pętli zawiera opcjonalną else:
klauzulę:
for val in iterable:
do_something(val)
else:
clean_up()
Treść else
klauzuli jest dobrym miejscem dla niektórych rodzajów działań czyszczących i jest wykonywana przy normalnym zakończeniu pętli: tj. Wychodzenie z pętli za pomocą return
lub break
pomijanie else
klauzuli; wyjście po continue
wykonaniu go. Wiem, że to tylko dlatego, że po prostu spojrzał go (jeszcze raz), bo nie pamiętam kiedyelse
klauzula jest wykonywany.
Zawsze? Na „awarii” pętli, jak sama nazwa wskazuje? Na regularne wypowiedzenie? Nawet jeśli pętla zostanie zakończona za pomocą return
? Nigdy nie mogę być całkowicie pewien bez szukania.
Winę za utrzymującą się niepewność else
obarczam wyborem słowa kluczowego: dla tej semantyki uważam to za niezwykle niememoniczne. Moje pytanie nie brzmi „dlaczego to słowo kluczowe jest używane do tego celu” (które prawdopodobnie zagłosowałbym za jego zamknięciem, chociaż dopiero po przeczytaniu odpowiedzi i komentarzy), ale jak mogę myśleć o tym else
słowie kluczowym, aby jego semantyka miała sens, i ja pamiętasz to?
Jestem pewien, że odbyło się sporo dyskusji na ten temat i mogę sobie wyobrazić, że wybór został dokonany w celu zachowania spójności z klauzulą try
oświadczenia else:
(którą również muszę sprawdzić) i aby nie dodawać do listy Zastrzeżone słowa Pythona. Być może powody wyboru else
wyjaśnią jego funkcję i sprawią, że będzie ona bardziej niezapomniana, ale chcę połączyć nazwę z funkcją, a nie po wyjaśnieniach historycznych per se.
Odpowiedzi na to pytanie , które moje pytanie zostało na krótko zamknięte jako duplikat, zawiera wiele interesujących historii. Moje pytanie ma inne znaczenie (jak połączyć konkretną semantykę else
z wyborem słowa kluczowego), ale uważam, że powinien być gdzieś link do tego pytania.
źródło
else
środki w zasadzie „jeśli warunek nie kontynuacja”. W tradycyjnej pętli for warunkiem kontynuacji jest zazwyczaji < 42
, w którym to przypadku można wyświetlić tę część jakoif i < 42; execute the loop body; else; do that other thing
break
. Kanoniczny przypadek użycia występuje wtedy, gdy pętla szuka czegoś i pęka, gdy go znajdzie.else
Jest wykonywana tylko wtedy, gdy nic nie znaleziono.Odpowiedzi:
(Jest to inspirowane odpowiedzią @Mark Tolonen.)
if
Oświadczenie prowadzi swojąelse
klauzulę jeżeli jej warunek jest fałszywy. Identyczniewhile
pętla uruchamia klauzulę else, jeśli jej warunek ma wartość false.Ta reguła pasuje do opisanego zachowania:
break
instrukcję, wychodzisz z pętli bez oceny warunku, więc warunek nie może mieć wartości false i nigdy nie uruchamiasz klauzuli else.continue
instrukcję, ponownie oceniasz warunek i robisz dokładnie to, co normalnie na początku iteracji pętli. Tak więc, jeśli warunek jest spełniony, nadal zapętlasz, ale jeśli jest to fałsz, uruchom klauzulę else.return
, nie oceniają warunku i dlatego nie uruchamiają klauzuli else.for
pętle zachowują się w ten sam sposób. Wystarczy uznać warunek za prawdziwy, jeśli iterator zawiera więcej elementów, lub fałsz w przeciwnym razie.źródło
elif
stwierdzeń. Odpowiedź na to pytanie brzmi: ma jeden głos w sieci.break
, w którym to przypadkuelse
nie uruchomiłby się, ale warunek jest False. Podobnie w przypadkufor
pętli może to dotyczyćbreak
ostatniego elementu.Lepiej pomyśleć o tym w ten sposób:
else
Blok zawsze będzie wykonywany, jeśli wszystko pójdzie dobrze w poprzednimfor
bloku, tak że osiągnie wyczerpanie.Właśnie w tym kontekście oznacza nie
exception
, niebreak
, niereturn
. Wszelkie instrukcje, które przejmują kontrolęfor
, powodująelse
ominięcie bloku.Typowy przypadek użycia występuje przy wyszukiwaniu elementu w
iterable
, dla którego wyszukiwanie jest albo odwołane, gdy element zostanie znaleziony, albo"not found"
flaga zostanie podniesiona / wydrukowana za pomocą następującegoelse
bloku:continue
Nie hijack sterowanie zfor
, więc kontrola przystąpi doelse
pofor
wyczerpaniu.źródło
else
, że zostanie wykonana klauzula, gdy coś pójdzie nie tak, prawda? Znowu się mylę ...else
]”, ponieważelse
jest uruchamiane, gdy żaden z warunków w pętli for nie ocenia się na True, jak wykazałem w mojej odpowiedziFalse
. Pytanie o to, jakfor
jest rozbite, zależy od przypadku użycia.else
Pythona).else
Udostępniasz dobre intuicyjne podsumowanie tego, co robi @Moses, ale nie pokazuje, w jaki sposób możemy powiązać to zachowanie z „innym”. Gdyby użyć innego słowa kluczowego (np.nobreak
Jak wspomniano w tej odpowiedzi na powiązane pytanie), łatwiej byłoby zrozumieć.if
/ mawhile
wartość false lub niefor
ma elementów.break
istnieje pętla zawierająca (poelse
).continue
wraca i ponownie ocenia stan pętli.Kiedy
if
wykonuje sięelse
? Gdy jego warunek jest fałszywy. Jest dokładnie tak samo dlawhile
/else
. Możesz więc myśleć owhile
/else
jako po prostu oif
tym, że działa w stanie prawdziwym, dopóki nie oceni wartości false. Abreak
to nie zmienia. Po prostu wyskakuje z pętli zawierającej bez oceny.else
Jest wykonywana tylko wtedy, gdy oceny wif
/while
warunek jest fałszywy.for
Jest podobna, z wyjątkiem jej warunek jest fałszywy wyczerpując swój iterator.continue
ibreak
nie wykonujelse
. To nie jest ich funkcja.break
Zamyka pętlę zawierającą.continue
Sięga do górnej części zawierającej pętli, gdzie warunek pętli jest uwzględniany. Jest to czynność ocenianiaif
/while
fałszowania (lubfor
nie ma już żadnych elementów), która jest wykonywanaelse
i nie ma innego sposobu.źródło
else
klauzula jest wykonywana, jeśli pętla zostanie zakończonacontinue
(lub normalnie), ale nie, jeśli wyjdziemy zbreak
. Te subtelności są powodem, dla którego naprawdę próbuję zrozumieć, coelse
łapie, a co nie.Oto, co zasadniczo oznacza:
To przyjemniejszy sposób pisania tego wspólnego wzoru:
else
Klauzula nie zostanie wykonane, jeśli istniejereturn
, ponieważreturn
liści funkcja, jak to ma na celu. Jedynym wyjątkiem od tego, o czym możesz myśleć, jest tofinally
, którego celem jest upewnienie się, że zawsze jest wykonywana.continue
nie ma nic wspólnego z tą sprawą. Powoduje to, że bieżąca iteracja pętli kończy się, co może się zdarzyć, aby zakończyć całą pętlę, i oczywiście w tym przypadku pętla nie została zakończona przezbreak
.try/else
jest podobny:źródło
Jeśli myślisz o swoich pętlach jako o strukturze podobnej do tej (nieco pseudo-kod):
może to mieć trochę więcej sensu. Pętla jest w gruncie rzeczy tylko
if
instrukcją powtarzaną do momentu spełnienia warunkufalse
. I to jest ważny punkt. Pętla sprawdza swój stan i widzi, że jestfalse
, a zatem wykonujeelse
(tak jak normalnieif/else
), a następnie wykonuje pętlę.Zauważ więc, że
else
jedyny get jest wykonywany, gdy warunek jest sprawdzany . Oznacza to, że jeśli wyjdziesz z ciała pętli w trakcie wykonywania, na przykład za pomocą areturn
lub abreak
, ponieważ warunek nie jest ponownie sprawdzany,else
sprawa nie zostanie wykonana.Z
continue
drugiej strony A zatrzymuje bieżące wykonanie, a następnie przeskakuje z powrotem, aby ponownie sprawdzić stan pętli, i dlategoelse
można to osiągnąć w tym scenariuszu.źródło
end
etykietę i po prostu włóżgoto loop
wnętrzeif
. Może nawet nieprzyzwoity, umieszczając tenif
sam wiersz na etykiecie, i nagle wygląda bardzo podobnie do oryginału.Moja chwila z
else
klauzulą pętli miała miejsce, gdy oglądałem rozmowę Raymonda Hettingera , który opowiedział historię o tym, jak według niego powinien się nazywaćnobreak
. Spójrz na poniższy kod, jak myślisz, co by to zrobił?Jak myślisz, co to robi? Cóż, ta część, która mówi,
nobreak
byłaby wykonana tylko wtedy, gdybybreak
instrukcja nie została trafiona w pętlę.źródło
Zwykle myślę o takiej strukturze pętli:
Aby być podobnym do zmiennej liczby
if/elif
instrukcji:W tym przypadku
else
instrukcja w pętli for działa dokładnie tak samo, jakelse
instrukcja w łańcuchuelif
s, jest wykonywana tylko wtedy, gdy żaden z warunków przed jej oceną na True. (lub przerwanie wykonania zreturn
lub wyjątek) Jeśli moja pętla nie pasuje do tej specyfikacji, zwykle rezygnuję z używaniafor: else
z dokładnie tego powodu, dla którego opublikowałeś to pytanie: jest to nieintuicyjne.źródło
Inni już wyjaśnili mechanikę
while/for...else
, a odniesienie do języka Python 3 ma autorytatywną definicję (patrz podczas i po ), ale oto mój osobisty mnemonik, FWIW. Wydaje mi się, że kluczem było dla mnie podzielenie tego na dwie części: jedną dla zrozumienia znaczeniaelse
relacji warunkowej w pętli i jedną dla zrozumienia kontroli pętli.Najłatwiej jest zacząć od zrozumienia
while...else
:for...else
Mnemonic jest zasadniczo taka sama:W obu przypadkach
else
część jest osiągana tylko wtedy, gdy nie ma już więcej elementów do przetworzenia, a ostatni element został przetworzony w zwykły sposób (tj. Brakbreak
lubreturn
). Pocontinue
prostu wraca i sprawdza, czy jest więcej przedmiotów. Mój mnemonik tych reguł dotyczy zarównowhile
ifor
:- „zwrot z powrotem do początku” oznacza oczywiście początek pętli, w której sprawdzamy, czy w iteracji jest więcej elementów, jeśli chodzi o
else
to, tocontinue
tak naprawdę nie odgrywa żadnej roli.źródło
else
Może być również wykorzystywany do zrobienia czegoś, gdy jesteś po prostu wykończony z wszystkich przedmiotów. Przykłady obejmują pisanie wpisu dziennika, aktualizację interfejsu użytkownika lub sygnalizowanie innego zakończonego procesu. Cokolwiek, naprawdę. Ponadto niektóre fragmenty kodu zakończone są „udanym” zakończeniembreak
wewnątrz pętli ielse
służą do obsługi przypadku „błędu”, w którym podczas iteracji nie znalazłeś żadnego odpowiedniego elementu (być może właśnie tak myślałeś z?).else
bloku pętli lub śledzić wynik przy użyciu innych środków. Zasadniczo się zgadzam, mówię tylko, że nie wiem, w jaki sposób ludzie korzystają z tej funkcji, dlatego chciałbym uniknąć zakładania, czyelse
scenariusz „ obsługuje przypadek pomyślny”, czy scenariusz „else
obsługuje przypadek nieudany” jest bardziej powszechny. Ale masz rację, więc komentuj z góry!W rozwoju opartym na testach (TDD), używając paradygmatu Priorytet transformacji , traktujesz pętle jako uogólnienie instrukcji warunkowych.
Podejście to dobrze łączy się z tą składnią, jeśli weźmie się pod uwagę tylko proste
if/else
(nieelif
) instrukcje:uogólnia na:
ładnie.
W innych językach kroki TDD od pojedynczej skrzynki do skrzynek ze zbiorami wymagają więcej refaktoryzacji.
Oto przykład z blogu 8thlight :
W powiązanym artykule na blogu 8thlight rozważono kata zawijania słów: dodawanie podziałów wierszy do ciągów (
s
zmienna we fragmentach poniżej), aby dopasować je do określonej szerokości (length
zmienna we fragmentach poniżej). W pewnym momencie implementacja wygląda następująco (Java):a następny test, który obecnie się nie powiedzie, to:
Mamy więc kod, który działa warunkowo: po spełnieniu określonego warunku dodawany jest podział wiersza. Chcemy ulepszyć kod, aby obsługiwał wiele podziałów linii. Rozwiązanie przedstawione w artykule proponuje zastosowanie transformacji (if-> while) , jednak autor komentuje:
co zmusza do wprowadzenia większej liczby zmian w kodzie w kontekście jednego testu zakończonego niepowodzeniem:
W TDD chcemy napisać jak najmniej kodu, aby testy przebiegły pomyślnie. Dzięki składni Pythona możliwa jest następująca transformacja:
z:
do:
źródło
Tak, jak to widzę,
else:
odpala, gdy iterujesz za końcem pętli.Jeśli
break
lubreturn
czyraise
nie zrobić iterate poza końcem pętli, ty immeadiately zatrzymać, a więcelse:
blok nie zostanie uruchomiony. Jeślicontinue
nadal wykonujesz iterację poza końcem pętli, ponieważ kontynuuj, po prostu przejdź do następnej iteracji. To nie zatrzymuje pętli.źródło
goto
najwyższym wynikiem ). Ale to krótsza wersja najlepiej głosowanej odpowiedzi ...Pomyśl o
else
klauzuli jako o części konstrukcji pętli;break
całkowicie zrywa z konstrukcji pętli, a tym samym pomijaelse
klauzulę.Ale tak naprawdę, moim mapowaniem mentalnym jest po prostu to, że jest to „strukturalna” wersja wzorca C / C ++:
Więc kiedy go napotykam
for...else
lub piszę, zamiast rozumieć go bezpośrednio , mentalnie tłumaczę to na powyższe rozumienie wzorca, a następnie sprawdzam, które części mapy składni Pythona odwzorowują na które części wzorca.(„Strukturyzowane” umieszczam w przestraszonych cudzysłowach, ponieważ różnica nie polega na tym, czy kod jest ustrukturyzowany czy nieustrukturyzowany, ale tylko na tym, czy dla danej struktury są słowa kluczowe i gramatyka)
źródło
else
? Jeśli miałeś na myślidone:
etykietę jako proxy lubelse:
, myślę, że masz ją dokładnie odwrotnie.done:
etykiecie. Być może najlepiej jest powiedzieć, że ogólna zgodność: Python ma konstrukcjęelse
-on-loop, dzięki czemu można wyrazić ten wzorzec przepływu sterowania bezgoto
.else
unika.Jeśli połączysz się
else
w paręfor
, może to być mylące. Nie sądzę, aby słowo kluczoweelse
było doskonałym wyborem dla tej składni, ale jeśli połączysz sięelse
z tym,if
co zawierabreak
, możesz zobaczyć, że ma to sens.else
jest mało przydatne, jeśli nie ma poprzedzającegoif
oświadczenia i uważam, że właśnie dlatego projektant składni wybrał to słowo kluczowe.Pokażę to w ludzkim języku.
źródło
Sposób, w jaki o tym myślę, jest kluczem do rozważenia znaczenia
continue
zamiastelse
.Inne słowa kluczowe, o których wspominasz, wychodzą z pętli (wychodzą nienormalnie)
continue
nie, po prostu pomijają resztę bloku kodu wewnątrz pętli. Fakt, że może poprzedzać zakończenie pętli, jest przypadkowy: zakończenie odbywa się w normalny sposób poprzez ocenę wyrażenia warunkowego w pętli.Musisz tylko pamiętać, że
else
klauzula jest wykonywana po normalnym zakończeniu pętli.źródło
źródło