Как я могу понять предложение "else" циклов Python?

многие программисты Python, вероятно, не знают, что синтаксис while петли и for петли включает в себя дополнительный else: статья:

for val in iterable:
    do_something(val)
else:
    clean_up()

тело else предложение является хорошим местом для определенных видов действий очистки и выполняется при нормальном завершении цикла: т. е., выход из цикла с return или break переход else предложение; выход после continue выполняет его. Я знаю это только потому, что я просто посмотрел (пока опять же), потому что я никогда не могу вспомнить , когда the else пункт выполняется.

всегда? О "провале" цикла, как следует из названия? На обычном увольнении? Даже если цикл выходит с return? Я никогда не могу быть полностью уверен, не посмотрев его.

я виню свою сохраняющуюся неопределенность в выборе ключевого слова: я нахожу else невероятно unmnemonic для этой семантики. Мой вопрос не "почему это ключевое слово используется для этой цели" (который я вероятно, проголосовали бы за закрытие, хотя только после прочтения ответов и комментариев), но как я могу думать о else ключевое слово, чтобы его семантика имела смысл, и поэтому я могу его запомнить?

я уверен, что об этом было много дискуссий, и я могу себе представить, что выбор был сделан для согласованности с try заявление else: предложение (которое я также должен посмотреть), и с целью не добавлять в список зарезервированных Python слова. Возможно, причины выбора else прояснит свою функцию и сделает ее более запоминающейся, но я после подключения имени к функции, а не после исторического объяснения как такового.

ответы этот вопрос, который мой вопрос был кратко закрыт как дубликат, содержит много интересной предыстории. Мой вопрос имеет другой фокус (как подключить конкретную семантику else С выбором ключевого слова), но я чувствую, что должна быть ссылка на этот вопрос где-то.

14 ответов


(это вдохновлено ответом @Mark Tolonen.)

An if оператор запускает свой else предложение, если его условие равно false. Тождественно, a while loop запускает предложение else, если его условие равно false.

это правило соответствует описанному вами поведению:

  • при нормальном выполнении цикл while многократно выполняется, пока условие не будет равно false, и поэтому при естественном выходе из цикла выполняется else пункт.
  • при выполнении break оператор, вы выходите из цикла без оценки условия, поэтому условие не может оцениваться как false, и вы никогда не запускаете предложение else.
  • при выполнении continue оператор, вы снова оцениваете условие и делаете именно то, что обычно делали бы в начале итерации цикла. Итак, если условие истинно, вы продолжаете цикл, но если оно ложно, вы запускаете предложение else.
  • другие методы выход из цикла, например return, не оценивайте условие и поэтому не запускайте предложение else.

for петли ведут себя одинаково. Просто учитывайте состояние как true, если итератор имеет больше элементов, или false в противном случае.


лучше думать об этом так:else блок всегда будет выполнено, если все пойдет право в предыдущем for блок такой, что он достигает истощения.

право в этом контексте означает нет exception, нет break, нет return. Любое заявление, которое захватывает контроль из for вызывает else блок, который нужно обойти.


общий случай использования при поиске элемента в iterable, для которого поиск либо отменяется, когда элемент найден, либо "not found" флаг поднят / напечатан через следующее else блок:

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

A continue не захватывает управление из for, поэтому управление перейдет к else после for исчерпан.


когда if выполнить else? Когда условие ложно. Это точно то же самое для while/else. Так что вы можете думать о while/else Как только if который продолжает работать в своем истинном состоянии, пока не оценит false. А break ничего не меняет. Это просто скачки содержащего цикла без оценки. The else выполняется только если оценка the if/while условие ложно.

на for is аналогично, за исключением того, что его ложное условие исчерпывает его итератор.

continue и break не выполнять else. Это не их функция. The break выходит из содержащего цикла. The continue возвращается в верхнюю часть содержащего цикла, где оценивается условие цикла. Это акт оценки if/while false (или for больше нет элементов), который выполняет else и нет другого пути.


вот что это по существу означает:

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

это более приятный способ написания этой общей картины:

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

на else предложение не будет выполнено, если есть return, потому что return оставляет функцию, как она предназначена. Единственное исключение из того, о чем вы можете думать, - это finally, чья цель состоит в том, чтобы быть уверенным, что он всегда выполняется.

continue не имеет ничего общего с этим вопросом. Оно вызывает ток итерация цикла до конца, которая может привести к завершению всего цикла, и, очевидно, в этом случае цикл не был завершен break.

try/else аналогично:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

если вы думаете о своих циклах как о структуре, подобной этой (несколько псевдо-код):

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

это может иметь немного больше смысла. Цикл по существу просто if оператор, который повторяется до тех пор, пока условие не false. И это важный момент. Цикл проверяет свое состояние и видит, что это false, таким образом, выполняет else (так же, как нормальный if/else), а затем цикл выполняется.

отметим, что else только get выполняется при проверке условия. Это означает, что если вы выходите из тела цикла в середине исполнения, например,return или break, так как условие не проверяется,else дело не будет выполнено.

A continue С другой стороны, останавливает текущее выполнение, а затем возвращается, чтобы снова проверить состояние цикла, поэтому else может быть достигнуто в этом случае.


мой момент с петлей else предложение было, когда я смотрел разговор Компания Raymond Hettinger, который рассказал историю о том, как, по его мнению, она должна была называться nobreak. Взгляните на следующий код, как вы думаете он будет делать?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

как вы думаете, что он делает? Ну, та часть, которая говорит nobreak будет выполняться только если break заявление не попало в петлю.


обычно я склонен думать о структуре цикла, как это:

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

чтобы быть похожим на переменное число if/elif отчетность:

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

в этом случае else оператор на цикле for работает точно так же, как else заявление по цепочке elifs, он выполняется только в том случае, если ни одно из условий перед его оценкой не равно True. (или прервать выполнение с помощью return или исключение) если мой цикл не соответствует этой спецификации, как правило, я выбираю отказаться от используя for: else по той же причине, по которой вы опубликовали этот вопрос: он не интуитивно понятен.


другие уже объяснили механику while/for...else и Python 3 ссылка на язык есть авторитетное определение (см. пока и на), но вот моя личная мнемоника, FWIW. Я думаю, ключом для меня было разбить это на две части: одна для понимания значения else по отношению к условному циклу и один для понимания управления циклом.

мне проще начать с понимание while...else:

while у вас есть больше деталей, делать вещи, else Если вы закончите, сделайте это

на for...else мнемоника в основном то же самое:

for каждый пункт, делать вещи, но else Если вы закончите, сделайте это

в обоих случаях else часть достигается только после того, как больше нет элементов для обработки, и последний элемент был обработан в обычным образом (т. е. без break или return). А continue просто возвращается и видит, есть ли еще какие-либо элементы. Моя мнемоника для этих правил относится к обоим while и for:

, когда breaking или returnИнг, там ничего else делать
и когда я говорю continue, это "цикл назад, чтобы начать" для вас

- С "loop back to start" означает, очевидно, начало цикла, где мы проверяем, есть ли есть ли еще элементы в iterable, так как else обеспокоен, continue действительно не играет никакой роли.


на


как я это вижу,else: срабатывает, когда вы проходите мимо конца цикла.

если вы break или return или raise вы не проходите мимо конца цикла, вы останавливаетесь immeadiately, и, таким образом,else: блок не будет работать. Если ты ... --5--> вы все еще повторяете конец цикла, так как continue просто переходит к следующей итерации. Это не останавливает петлю.


думать else предложение как часть конструкции цикла;break полностью выходит из конструкции цикла и, таким образом, пропускает else предложения.

но на самом деле, мое ментальное отображение просто в том, что это "структурированная" версия шаблона C/C++ pattern:

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

поэтому, когда я сталкиваюсь с for...else или писать его самому, а не понимать его.напрямую, Я мысленно перевожу его в вышеупомянутое понимание шаблона, а затем работаю какие части синтаксиса python сопоставляются с какими частями шаблона.

(я ставлю "структурированный" в кавычки, потому что разница не в том, структурирован ли код или неструктурирован, а просто есть ли ключевые слова и грамматика, посвященные конкретной структуре)


как я думаю об этом, ключ должен учитывать значение continue, а не else.

другие ключевые слова, которые вы упоминаете вырваться из цикла (выход ненормально) в то время как continue нет, он просто пропускает оставшуюся часть блока кода внутри цикла. Тот факт, что он может предшествовать завершению цикла, является случайным: завершение фактически выполняется обычным способом путем оценки условного выражения цикла.

тогда вам просто нужно помнить, что the else предложение выполняется после завершения обычного цикла.


если вы пытаетесь выполнить сопряжение else с for в вашем уме, это может сбить с толку. Я не думаю, что ключевое слово else был отличным выбором для этого синтаксиса, но если вы соедините else с break, вы можете видеть, что это действительно имеет смысл.

позвольте мне продемонстрировать это на человеческом языке.

for каждый человек в группе подозреваемых if любой преступник break следствие. else отчет неудача.


else едва ли полезно, если бы не break на for цикл в любом случае.


# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''