Как я могу понять предложение "else" петель Python?
многие программисты Python, вероятно, не знают, что синтаксис while петли и for петли включает в себя дополнительный else: статья:
for val in iterable:
do_something(val)
else:
clean_up()
тело else предложение является хорошим местом для определенных видов действий очистки и выполняется при нормальном завершении цикла: т. е., выход из цикла с return или break переход else предложение; выход после a continue выполняет его. Я знаю это только потому, что я просто посмотрел (пока опять же), потому что я никогда не могу вспомнить , когда the else пункт выполняется.
всегда? На "провал" цикла, как следует из названия? По обычному увольнению? Даже если цикл завершается с return? Я никогда не могу быть полностью уверен, не посмотрев его.
я виню свою сохраняющуюся неопределенность в выборе ключевого слова: я нахожу else невероятно немногословно для этой семантики. Мой вопрос не "почему это ключевое слово используется для этой цели" (который я вероятно, проголосовали бы за закрытие, хотя только после прочтения ответов и комментариев), но как я могу думать о else ключевое слово, чтобы его семантика имела смысл, и поэтому я могу его запомнить?
я уверен, что было много дискуссий об этом, и я могу себе представить, что выбор был сделан для согласованности с try заявление else: предложение (которое я также должен посмотреть), и с целью не добавлять в список зарезервированных Python слова. Возможно, причины выбора else прояснит его функцию и сделает ее более запоминающейся, но я после подключения имени к функции, а не после исторического объяснения как такового.
ответы на этот вопрос, который мой вопрос был кратко закрыт как дубликат, содержат много интересной предыстории. Мой вопрос имеет другой фокус (как подключить конкретную семантику else С выбором ключевого слова), но я чувствую, что должна быть ссылка на этот вопрос где-то.
14 ответов:
(это вдохновлено ответом @Mark Tolonen.)
An
ifоператор запускает егоelseпредложение, если его условие оценивается как false. Тож, аwhileцикл выполняется предложение else, если condition имеет значение false.это правило соответствует описанному вами поведению:
- в обычном исполнении цикл while повторяется до тех пор, пока условие не будет оценено как false, и поэтому, естественно, выход из цикла запускает else пункт.
- при выполнении
breakоператор, вы выходите из цикла без оценки условия, поэтому условие не может быть оценено как false, и вы никогда не запускаете предложение else.- при выполнении
continueоператор, вы снова оцениваете условие и делаете именно то, что обычно делаете в начале итерации цикла. Итак, если условие истинно, вы продолжаете цикл, но если оно ложно, вы запускаете предложение else.- другие методы выход из цикла, например
return, не оценивайте условие и поэтому не запускайте предложение else.
forпетли ведут себя одинаково. Просто считайте условие истинным, если итератор имеет больше элементов, или ложным в противном случае.
лучше думать об этом так:
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ничего не меняет. Он просто прыгает из содержащего цикла без оценки. Элементelseвыполняется только если оценка theif/whileусловие ложно.The
foris подобное, за исключением его ложного условия, исчерпывает его итератор.
continueиbreakне выполнятьelse. Это не их функция. Элементbreakвыход из содержащего цикла. Элементcontinueвозвращается в верхнюю часть содержащего цикла, где вычисляется условие цикла. Это акт оценкиif/whilefalse (илиforне имеет больше элементов), который выполняетelseи никак иначе.
вот что это по существу означает:
for/while ...: if ...: break if there was a break: pass else: ...это более приятный способ написания этого общего шаблона:
found = False for/while ...: if ...: found = True break if not found: ...The
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будет выполняться только если abreakзаявление не попало в петлю.
обычно я склонен думать о структуре цикла, как это:
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Если вы закончите, сделайте этоThe
for...elseмнемоника в основном то же самое:
forкаждый пункт, делать вещи, ноelseЕсли вы закончите, сделайте этов обоих случаях
elseчасть достигается только тогда, когда больше нет элементов для обработки, и последний элемент был обработан в a регулярным образом (т. е. нетbreakилиreturn). Аcontinueпросто возвращается и видит, если есть еще какие-либо элементы. Моя мнемоника для этих правил применима к обоимwhileиfor:, когда
breaking илиreturnИнг, нет ничегоelseделать
и когда я говорюcontinue, это "цикл назад, чтобы начать" для вас- С "цикл назад, чтобы начать" означает, очевидно, начало цикла, где мы проверяем, есть ли есть ли еще элементы в iterable, так как
elseобеспокоен,continueна самом деле не играет никакой роли вообще.
на разработка на основе тестов (TDD), при использовании Предпосылка Приоритета Преобразования парадигма, вы рассматриваете циклы как обобщение условных операторов.
этот подход хорошо сочетается с этим синтаксисом, если рассматривать только простые
if/else(неelif) заявления:if cond: # 1 else: # 2обобщается на:
while cond: # <-- generalization # 1 else: # 2красиво.
на других языках TDD переходит от одного случая к случаям с коллекции требуют большего рефакторинга.
вот пример 8thlight блог:
в связанной статье в блоге 8thlight рассматривается слово Wrap kata: добавление разрывов строк в строки (the
sпеременная в приведенных ниже фрагментах), чтобы они соответствовали заданной ширине (lengthпеременная в приведенных ниже фрагментах). В какой-то момент реализация выглядит следующим образом (Java):String result = ""; if (s.length() > length) { result = s.substring(0, length) + "\n" + s.substring(length); } else { result = s; } return result;и следующий тест, что в настоящее время терпит неудачу это:
@Test public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception { assertThat(wrap("verylongword", 4), is("very\nlong\nword")); }Итак, у нас есть код, который работает условно: при выполнении определенного условия добавляется разрыв строки. Мы хотим улучшить код для обработки нескольких разрывов строк. Решение, представленное в статье, предлагает применить (Если->а) преобразование, однако автор делает комментарий, что:
в то время как петли не могут иметь
elseпредложения, поэтому нам нужно устранитьelseпуть, делая меньше вifпуть. Опять же, это рефакторинг.что заставляет делать больше изменений в коде в контексте одного неудачного теста:
String result = ""; while (s.length() > length) { result += s.substring(0, length) + "\n"; s = s.substring(length); } result += s;в TDD мы хотим написать как можно меньше кода, чтобы тесты проходили. Благодаря синтаксису Python возможно следующее преобразование:
от:
result = "" if len(s) > length: result = s[0:length] + "\n" s = s[length:] else: result += sto:
result = "" while len(s) > length: result += s[0:length] + "\n" s = s[length:] else: result += s
как я это вижу,
else:срабатывает, когда вы проходите мимо конца цикла.если вы
breakилиreturnилиraiseвы не повторяете за конец цикла, вы останавливаетесь immeadiately, и таким образомelse:блок не будет работать. Если выcontinueвы все еще повторяете конец цикла, так как continue просто переходит к следующей итерации. Это не останавливает цикл.
думать
elseпредложение как часть конструкции цикла;breakвырывается из цикла конструкции полностью, и таким образом пропускаетelseпредложения.но на самом деле, мое ментальное отображение-это просто "структурированная" версия шаблона C/C++ pattern:
for (...) { ... if (test) { goto done; } ... } ... done: ...поэтому, когда я сталкиваюсь с
for...elseили написать его сам, а не понимать его напрямую, Я мысленно перевожу его в вышеупомянутое понимание шаблона, а затем работаю какие части синтаксиса python сопоставляются с какими частями шаблона.(я помещаю "структурированный" в кавычки страха, потому что разница заключается не в том, структурирован ли код или неструктурирован, а просто в том, есть ли ключевые слова и грамматика, посвященные конкретной структуре)
как я думаю об этом, ключ состоит в том, чтобы рассмотреть значение
continue, а неelse.другие ключевые слова, которые вы упоминаете вырваться из цикла (выход ненормально) в то время как
continueнет, он просто пропускает оставшуюся часть блока кода внутри цикла. Тот факт, что он может предшествовать завершению цикла, является случайным: завершение фактически выполняется обычным способом путем оценки условного выражения цикла.тогда вам просто нужно помнить, что элемент
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'] '''
Comments