Застереження Else на Python під час оператора


321

Я помітив, що наступний код є законним в Python. Моє запитання, чому? Чи є конкретна причина?

n = 5
while n != 0:
    print n
    n -= 1
else:
    print "what the..."

5
@detly: Це тому, що більшість людей уникають цієї конструкції. :) Я вважаю, що Гуїдо згадав під час процесу Py3k, що, принаймні, вибір слова elseдля цього використання був надзвичайно поганою ідеєю, і що вони більше цього не роблять.
Ніколас Найт

5
@Nicholas Knight - так, хоча б це було спокусливо, це, мабуть, було щось, що я зрозумів лише на перший погляд. Будь-який інший бідний сік повинен буде піти і подивитися на специфіку мови, або повернутися назад у часі і опублікувати питання тут на Sta- heeeeey ...
detly

8
Ідея вибору 'else' полягає в тому, що ця конструкція нібито часто використовується в поєднанні з 'if X: break' всередині циклу while. Оскільки пункт 'else' виконується, якщо ми не вийдемо з циклу, він утворює своєрідне сортування 'else' до 'if'.
Джонатан Хартлі

12
Вони повинні перейменувати це after:.
naught101

Відповіді:


388

elseПоложення виконується тільки , коли ваше whileстан стає хибним. Якщо ви breakвийшли з циклу, або якщо винято виняток, він не буде виконаний.

Один із способів подумати про це - як конструкція if / else щодо умови:

if condition:
    handle_true()
else:
    handle_false()

є аналогом контурної конструкції:

while condition:
    handle_true()
else:
    # condition is false now, handle and go on with the rest of the program
    handle_false()

Приклад може бути таким:

while value < threshold:
    if not process_acceptable_value(value):
        # something went wrong, exit the loop; don't pass go, don't collect 200
        break
    value = update(value)
else:
    # value >= threshold; pass go, collect 200
    handle_threshold_reached()

42
"Інше застереження виконується лише тоді, коли ваш режим while стає хибним." Формулювання тут передбачає, що ваш стан поки переходить із стану справжнього в хибне і тоді буде виконано інше. Однак, якщо час ніколи не відповідає дійсності, застереження про інше все одно буде виконуватися.
користувач597608

псевдокод Так виправте мене, якщо я помиляюся, але це точно так само, як while {} something за винятком того, що somethingбуде пропущено, якщо ви breakперебуваєте в whileциклі.
Даніель Каплан

2
Можливо, самим точним псевдокодом було б: while (True) {if (cond) {handle_true (); } else {handle_false (); перерва; }}
VinGarcia

2
"Не пройди, не збирай 200", ха-ха, всі, хто знає, звідки це, мали хороше дитинство
Стефан Октавіан

102

elseПункт виконується , якщо ви виходите з блоку зазвичай, натиснувши умова циклу або впасти на дно спробувати блоку. Це НЕ виконується , якщо ви breakабо returnз блоку, або викликати виключення. Він працює не тільки в той час, як і в циклі, але також пробує блоки.

Зазвичай ви знаходите його в місцях, де зазвичай ви виходите з циклу рано, а вибіг з кінця циклу - несподіваний / незвичний випадок. Наприклад, якщо ви переглядаєте список, шукаючи значення:

for value in values:
    if value == 5:
        print "Found it!"
        break
else:
    print "Nowhere to be found. :-("

1
Насправді досить корисна конструкція для такої речі. Не знаю, скільки разів я ставив found_it=Falseцикл на початку, а потім зробіть, якщо перевірити found_itв кінці
Cruncher

42

У відповідь на Is there a specific reason?це одне цікаве додаток: виривання декількох рівнів циклічного циклу.

Ось як це працює: зовнішній цикл має розрив на кінці, тому він би виконувався лише один раз. Однак, якщо внутрішній цикл завершується (не знаходить дільника), він доходить до оператора else і зовнішній розрив ніколи не досягається. Таким чином, розрив внутрішньої петлі вирветься з обох петель, а не лише з однієї.

for k in [2, 3, 5, 7, 11, 13, 17, 25]:
    for m in range(2, 10):
        if k == m:
            continue
        print 'trying %s %% %s' % (k, m)
        if k % m == 0:
            print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
            break
    else:
        continue
    print 'breaking another level of loop'
    break
else:
    print 'no divisor could be found!'

Для обох whileі forциклів elseоператор виконується в кінці, якщо breakвін не був використаний.

У більшості випадків є кращі способи зробити це (перетворивши його на функцію або збільшивши виняток), але це працює!


1
Я не став голосом, але я думаю, я знаю, чому хтось зробив. Ви не відповідаєте на запитання і надаєте 14 рядків коду лише з 2 рядками опису. Якщо є відповідне на поставлене запитання, ви нам не говорите ...
BlueEel

1
@BlueEel дякую за відгук! Я додав більше пояснень щодо коду, і я зрозумів, як це відповідає на питання (адже він відповідає на частину).
Марк

Вам вдалося поставити свій код у контексті, і хоча ви не відповідаєте на всі запитання, я зараз бачу актуальність. Я схвально відгукнувся на вашу відповідь, оскільки вона тепер корисна новачкам та новачкам (як і я щодо пітона). - Дякую, я щось навчився.
BlueEel

Мені подобається простий додаток - тепер я бачу, чому хтось може ним користуватися. Хоча я ніколи не бачив у цьому потреби.
Гейб

На прикладі показано використання для / else, але питання стосувалося спеціально while / else.
Ян Голдбі

20

Задача else виконується, коли умова while оцінюється як хибна.

З документації :

Оператор while використовується для повторного виконання, доки істинний вираз:

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

Це неодноразово перевіряє вираз і, якщо це правда, виконує перший набір; якщо вираз хибний (що може бути вперше його перевірити), набір elseпункту, якщо він присутній, виконується і цикл закінчується.

breakЗаява виконується в першому набору завершує цикл без виконання elseнабору Пункту в. continueЗаява виконується в першому пакету пропускає решту пакету і повертається до перевірки вираження.


15

Моя відповідь буде зосереджена на тому, КОГО ми можемо використовувати час / для іншого.

На перший погляд, здається, немає нічого різного при використанні

while CONDITION:
    EXPRESSIONS
print 'ELSE'
print 'The next statement'

і

while CONDITION:
    EXPRESSIONS
else:
    print 'ELSE'
print 'The next statement'

Тому що print 'ELSE'оператор, здається, завжди виконується в обох випадках (і тоді, коли whileцикл закінчується чи не працює).

Тоді, інше лише тоді, коли заява print 'ELSE'не буде виконана. Це коли знаходиться breakвсередині блоку коду підwhile

In [17]: i = 0

In [18]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
else:
    print 'ELSE'
print 'The next statement'
   ....:
0
1
2
The next statement

Якщо відрізняються:

In [19]: i = 0

In [20]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
print 'ELSE'
print 'The next statement'
   ....:
0
1
2
ELSE
The next statement

return не входить до цієї категорії, оскільки це робить однаковий ефект для двох вищезазначених випадків.

Підвищення винятку також не викликає різниці, тому що коли він піднімається, де наступний код буде виконуватися в обробнику винятків (крім блоку), код у elseпункті чи відразу після цього whileпункту не буде виконаний.


4

Я знаю, це старе питання, але ...

Як сказав Реймонд Хеттінгер, його слід називати while/no_breakзамість while/else.
Я легко підкреслюю, якщо ви подивитеся на цей фрагмент.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
if n == 0:
    print n

Тепер замість того, щоб перевіряти стан після циклу, поки ми можемо поміняти його elseі позбутися цієї перевірки.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
else:  # read it as "no_break"
    print n

Я завжди читаю це, while/no_breakщоб зрозуміти код, і цей синтаксис має для мене набагато більше сенсу.


3

Інше застереження виконується лише тоді, коли умова while стає хибною.

Ось кілька прикладів:

Приклад 1: Спочатку умова не відповідає дійсності, тому виконується умова .

i = 99999999

while i < 5:
    print(i)
    i += 1
else:
    print('this')

ВИХІД:

this

Приклад 2: поки умова i < 5 Герасимчука помилковим , оскільки i == 3перерви цикл, тому ще придаткових не був виконаний.

i = 0

while i < 5:
    print(i)
    if i == 3:
        break
    i += 1
else:
    print('this')

ВИХІД:

0
1
2
3

Приклад 3: У той час, коли умова i < 5 ставала помилковою, коли iбуло 5, тому інше було виконано.

i = 0

while i < 5:
    print(i)
    i += 1
else:
    print('this')

ВИХІД:

0
1
2
3
4
this

0

Оператор else:виконується, коли і лише тоді, коли цикл while більше не відповідає його умові (у вашому прикладі, коли n != 0false).

Отже, вихід буде таким:

5
4
3
2
1
what the...

Я знаю, але цей час поки / інше не працює на Java. Мені це здається досить цікавим, коли я зрозумів, що це працює в Python. Мені просто цікаво і хотілося дізнатися технічну причину.
Іван

6
@Ivan: Це не стільки те, що він не працює на Java, але і те, що він не існує в Java. Це можна зробити так, щоб хтось дбав про те, щоб додати його до мови.
Ігнасіо Васкес-Абрамс

1
Ні, поки False: .. else .. все ще виконує статтю else. Точніше сказати: інше не виконується лише в тому випадку, якщо цикл розірваний.
Лев Уфімцев

0

Else виконується, якщо цикл не розірвався.

Мені подобається думати про це з метафорою "бігуна".

"Інше" - це як перетинання фінішної лінії, незалежно від того, розпочали ви на початку чи в кінці траси. "else" не виконується лише в тому випадку, якщо ви зламаєте десь посередині.

runner_at = 0 # or 10 makes no difference, if unlucky_sector is not 0-10
unlucky_sector = 6
while runner_at < 10:
    print("Runner at: ", runner_at)
    if runner_at == unlucky_sector:
        print("Runner fell and broke his foot. Will not reach finish.")
        break
    runner_at += 1
else:
    print("Runner has finished the race!") # Not executed if runner broke his foot.

Основні випадки використання - це виривання вкладених циклів або якщо ви хочете запустити деякі оператори, лише якщо цикл десь не прорвався (думайте, що зламати незвичну ситуацію).

Наприклад, нижче є механізмом того, як вийти з внутрішнього циклу без використання змінних або спробувати / catch:

for i in [1,2,3]:
    for j in ['a', 'unlucky', 'c']:
        print(i, j)
        if j == 'unlucky':
            break
    else: 
        continue  # Only executed if inner loop didn't break.
    break         # This is only reached if inner loop 'breaked' out since continue didn't run. 

print("Finished")
# 1 a
# 1 b
# Finished

-1

Краще використовувати 'while: else:' побудова в Python має бути, якщо цикл не виконується в 'while', тоді виконується оператор 'else'. Те, як він працює сьогодні, не має сенсу, оскільки ви можете використовувати код нижче з тими ж результатами ...

n = 5
while n != 0:
    print n
    n -= 1
print "what the..."

8
Ні, різниця полягає в тому, що elseблок не буде виконуватися, якщо ви залишаєте цикл за допомогою breakабо returnключового слова. У вашому прикладі printбуде виконуватися також, якщо цикл закінчився breakкомандою.
notsurewhattodo

2
Ви описуєте, як більшість людей бажають, щоб функція працювала, а не як вона насправді працює!
dotancohen

-2

Це корисно для соціальної взаємодії.

while (Date != "January 1st"):
    time.sleep(1)
else:
    print("Happy new year!")

2
І яка саме мета elseтут? Код робить точно так само без нього.
wovano

Якщо ваш годинник та календар breakпід час відліку часу, його використання elseне змусить вас сказати "З новим роком!" миттєво, що не має сенсу.
Гімуте

@Guimote, що ти маєш на увазі "якщо ваш годинник та календар break"? У breakкоді немає.
wovano
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.