Почему python использует «else» после циклов for и while?

Ниже приведен пример класса оболочки вокруг Enum. Я немного странный bu - то, что мне нужно:

public class W2UIEnum<T extends Enum<T> & Resumable> {

public String id;
public String caption;

public W2UIEnum(ApplicationContext appContext, T t) {
    this.id = t.getResume();
    this.caption = I18N.singleInstance.getI18nString(t.name(), "enum_"
            + t.getClass().getSimpleName().substring(0, 1).toLowerCase()
            + t.getClass().getSimpleName().substring(1,
                    t.getClass().getSimpleName().length()), appContext
            .getLocale());
}

public static <T extends Enum<T> & Resumable> List<W2UIEnum<T>> values(
        ApplicationContext appContext, Class<T> enumType) {
    List<W2UIEnum<T>> statusList = new ArrayList<W2UIEnum<T>>();
    for (T status : enumType.getEnumConstants()) {
        statusList.add(new W2UIEnum(appContext, status));
    }
    return statusList;
}

}

377
задан Wolf 28 November 2014 в 10:40
поделиться

21 ответ

Это странная конструкция даже для опытных программистов Python. При использовании в сочетании с циклами for это в основном означает «найти какой-либо элемент в итерируемом элементе, в противном случае, если ничего не найдено, do ...». Как в:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

Но всякий раз, когда вы видите эту конструкцию, лучшей альтернативой является либо инкапсуляция поиска в функции:

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

, либо использование списка:

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

Он не семантически эквивалентен двум другим версиям, но работает достаточно хорошо в не критичном к производительности коде, где не имеет значения, повторяете ли вы весь список или нет. Другие могут не согласиться, но я бы лично не использовал блоки for-else или while-else в производственном коде.

См. Также [Python-ideas] Краткое содержание for ... else threads

223
ответ дан phoenix 28 November 2014 в 10:40
поделиться

Я рассматриваю структуру как для (если) A else B, так и для (if) -sese является специальным if-else , примерно . Это может помочь понять еще .

A и B выполняются не более одного раза, что аналогично структуре if-else.

for (if) может рассматриваться как специальное условие if, которое выполняет цикл для выполнения условия if. Как только условие , если выполнено, A и нарушают ; Остальное , Б.

-1
ответ дан Jie Zhang 28 November 2014 в 10:40
поделиться

Python использует циклы else after for и while, так что если к циклу ничего не применяется, происходит что-то еще. Например:

test = 3
while test == 4:
     print("Hello")
else:
     print("Hi")

Вывод будет «Привет» снова и снова (если я прав).

0
ответ дан Mrmongoose64 28 November 2014 в 10:40
поделиться
1112 Я просто пытался разобраться в этом сам. Я обнаружил, что следующее помогает!

• Думайте о else как о паре с if внутри цикла (а не с for) - если условие выполнено, разорвать цикл, иначе сделайте это - за исключением одного else в паре с несколькими if с!
• Если if не было выполнено вообще, то выполните else.
• Множественные if с можно также рассматривать как if - elif с!

0
ответ дан Germaine Goh 28 November 2014 в 10:40
поделиться

Великолепные ответы:

  • это , которые объясняют историю, и
  • этот дает правильное цитирование, чтобы облегчить ваш перевод /understanding.

Моя заметка здесь взята из того, что однажды сказал Дональд Кнут (извините, не могу найти ссылку), что существует конструкция, в которой while-else неотличима от if-else, а именно (в Python):

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

имеет тот же поток (исключая различия низкого уровня) как:

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

Дело в том, что if-else может рассматриваться как синтаксический сахар для while-else, который имеет неявный break в конец его if блока. Противоположный вывод, что цикл while является расширением до if, более распространен (это просто повторная / циклическая условная проверка), потому что if часто преподается раньше while. Однако это не так, потому что это будет означать, что блок else в while-else будет выполняться каждый раз , когда условие ложно.

Чтобы облегчить ваше понимание, подумайте об этом так:

Без break, return и т. Д. Цикл заканчивается только тогда, когда условие больше не выполняется, и в таком случае else Блок также будет выполнен один раз. В случае Python for вы должны рассмотреть циклы в стиле C for (с условиями) или перевести их в while.

Еще одно примечание:

Преждевременное break, return и т. Д. Внутри цикла делает невозможным для условия стать ложным, потому что выполнение выпрыгнуло из цикла, в то время как условие было истинным и он никогда не вернется, чтобы проверить это снова.

1
ответ дан WloHu 28 November 2014 в 10:40
поделиться
for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

«иначе» здесь безумно просто, просто имейте в виду

1, «если for clause завершено»

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
if "for clause is completed":
    print("Completed successfully")

Имеется возможность написать такие длинные операторы как « поскольку предложение завершено ", поэтому они вводят" еще ".

else здесь, если по своей природе.

2, однако, как насчет for clause is not run at all

In [331]: for i in range(0):
     ...:     print(i)
     ...: 
     ...:     if i == 9:
     ...:         print("Too big - I'm giving up!")
     ...:         break
     ...: else:
     ...:     print("Completed successfully")
     ...:     
Completed successfully

Так что это полностью утверждение - логическая комбинация:

if "for clause is completed" or "not run at all":
     do else stuff

или, если говорить так:

if "for clause is not partially run":
    do else stuff

или так:

if "for clause not encounter a break":
    do else stuff
1
ответ дан Algebra 28 November 2014 в 10:40
поделиться

Вот еще один идиоматический вариант использования помимо поиска. Допустим, вы хотели подождать, пока условие будет выполнено, например, порт, который будет открыт на удаленном сервере, а также некоторое время ожидания. Тогда вы можете использовать конструкцию while...else следующим образом:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()
1
ответ дан Jonathan Sudiaman 28 November 2014 в 10:40
поделиться

Вы можете думать об этом, как, else как в остальной части материала, или другой материал, который не был сделан в цикле.

2
ответ дан jamylak 28 November 2014 в 10:40
поделиться

Вот способ подумать о том, что я не видел, чтобы кто-то еще упоминал выше:

Во-первых, помните, что for-циклы - это просто синтаксический сахар вокруг while-циклов. Например, цикл

for item in sequence:
    do_something(item)

можно переписать (приблизительно) как

item = None
while sequence.hasnext():
    item = sequence.next()
    do_something(item)

Во-вторых, помните, что циклы while в основном просто повторяются, если-блоки! Вы всегда можете прочитать цикл while как «если это условие истинно, выполнить тело, а затем вернуться и проверить снова».

Так что, хотя / else имеет смысл: это та же структура, что и if / else, с добавленной функциональностью зацикливания до тех пор, пока условие не станет ложным, вместо простой проверки условия один раз.

И тогда for / else также имеет смысл: поскольку все циклы for являются просто синтаксическим сахаром поверх циклов while, вам просто нужно выяснить, каково неявное условное выражение базового цикла while, а затем else соответствует когда это условие становится ложным.

4
ответ дан Aaron Gable 28 November 2014 в 10:40
поделиться

Ключевое слово else может сбивать с толку, и, как отмечают многие, что-то вроде nobreak, notbreak более уместно.

Чтобы логически понять for ... else ..., сравните его с try...except...else, а не if...else..., большинство программистов на python знакомы со следующим кодом:

try:
    do_something()
except:
    print("Error happened.") # The try block threw an exception
else:
    print("Everything is find.") # The try block does things just find.

Аналогично, подумайте о break ] как особый вид Exception:

for x in iterable:
    do_something(x)
except break:
    pass # Implied by Python's loop semantics
else:
    print('no break encountered')  # No break statement was encountered

Разница в python подразумевает except break и вы не можете выписать его, поэтому он становится:

for x in iterable:
    do_something(x)
else:
    print('no break encountered')  # No break statement was encountered

Да, я знаю, что это сравнение может быть трудным и утомительным, но оно проясняет путаницу.

4
ответ дан cizixs 28 November 2014 в 10:40
поделиться

Коды в блоке операторов else будут выполняться, когда цикл for не был прерван.

for x in xrange(1,5):
    if x == 5:
        print 'find 5'
        break
else:
    print 'can not find 5!'
#can not find 5!

Из документов: операторы break и continue, а также предложения о циклах

Операторы цикла могут содержать предложение else; он выполняется, когда цикл завершается из-за исчерпания списка (с помощью for) или когда условие становится ложным (с помощью while), но не тогда, когда цикл завершается оператором break. Это иллюстрируется следующим циклом, который ищет простые числа:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(Да, это правильный код. Посмотрите внимательно: предложение else принадлежит циклу for, а не оператору if.)

При использовании с циклом предложение else имеет больше общего с предложением else оператора try, чем с инструкциями if: предложение else оператора try выполняется, когда не возникает исключение, и else цикла Предложение выполняется, когда не происходит перерыв. Подробнее об операторе try и исключениях см. Обработка исключений.

Оператор continue, также заимствованный из C, продолжает следующую итерацию цикла:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9
4
ответ дан Mark Amery 28 November 2014 в 10:40
поделиться

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

5
ответ дан 0xc0de 28 November 2014 в 10:40
поделиться

Так как техническая часть получила довольно много ответов, мой комментарий как раз связан с путаницей , которая приводит к этому переработанному ключевому слову .

Будучи Python очень красноречивым языком программирования, злоупотребление ключевым словом более печально известно. Ключевое слово else прекрасно описывает часть потока дерева решений: «если вы не можете этого сделать, (иначе) сделайте это». Это подразумевается на нашем родном языке.

Вместо этого использование этого ключевого слова с утверждениями while и for создает путаницу. Причина, по которой наша карьера программиста научила нас тому, что утверждение else находится в дереве решений; его логическая область , обертка, которая условно возвращает путь, по которому нужно следовать. Между тем, циклические операторы имеют явно выраженную цель достичь чего-то. Цель достигается после непрерывных итераций процесса.

if / else указывают путь для следования . Петли следуют по пути, пока «цель» не будет достигнута .

Проблема в том, что else - это слово, которое четко определяет последний вариант в условии. Семантика слова этого слова совместно используется Python и Human Language. Но другое слово в человеческом языке никогда не используется для обозначения действий, которые кто-то или что-либо предпримет после того, как что-то будет выполнено. Он будет использоваться, если в процессе его завершения возникнет проблема (более похожая на инструкцию break ).

В конце ключевое слово останется в Python. Понятно, что это была ошибка, понятнее, когда каждый программист пытается придумать историю, чтобы понять ее использование как какое-то мнемоническое устройство. Я бы с удовольствием, если бы они выбрали вместо ключевого слова then. Я считаю, что это ключевое слово идеально вписывается в этот итеративный поток, выплату после цикла.

Это напоминает ту ситуацию, которая возникает у какого-то ребенка после выполнения каждого шага сборки игрушки: И ТО какой папа?

7
ответ дан 3rdWorldCitizen 28 November 2014 в 10:40
поделиться

Я прочитал это примерно так:

Если все еще на условиях для запуска цикла, делать вещи, еще делать что-то еще.

12
ответ дан pcalcao 28 November 2014 в 10:40
поделиться

Я думаю, что в документации есть отличное объяснение , иначе , продолжение

[...] выполняется, когда цикл завершается из-за исчерпания список (с помощью for) или когда условие становится ложным (с помощью while), но не тогда, когда цикл завершается оператором break. "

Источник: Документы Python 2: руководство по поток управления

14
ответ дан Paebbels 28 November 2014 в 10:40
поделиться

Для простоты вы можете думать об этом так:

  • Если в цикле for встречается команда break, часть else вызываться не будет.
  • Если он не встретит команду break в цикле for, будет вызвана часть else.

Другими словами, если итерация цикла не «нарушена» с break, будет вызвана часть else.

20
ответ дан Ad Infinitum 28 November 2014 в 10:40
поделиться

Самый простой способ, которым я нашел «получить» то, что сделал for / else, и, что более важно, когда его использовать, это сконцентрироваться на том, куда переходит оператор break. Конструкция For / else представляет собой один блок. Перерыв выпрыгивает из блока и, таким образом, перепрыгивает через условие else. Если бы содержимое предложения else просто следовало за предложением for, оно никогда бы не перепрыгнуло, и поэтому эквивалентную логику нужно было бы предоставить, поместив его в if. Это было сказано ранее, но не совсем в этих словах, так что это может помочь кому-то еще. Попробуйте запустить следующий фрагмент кода. Я искренне поддерживаю комментарий «без перерыва» для ясности.

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')
15
ответ дан Neil_UK 28 November 2014 в 10:40
поделиться

Потому что они не хотели вводить новое ключевое слово в язык. Каждый из них крадет идентификатор и вызывает проблемы обратной совместимости, поэтому обычно это последнее средство.

31
ответ дан Cat Plus Plus 28 November 2014 в 10:40
поделиться

Существует отличная презентация Раймона Хеттингера под названием Преобразование кода в красивый идиоматический Python , в которой он кратко рассматривает историю конструкции for ... else. Соответствующий раздел «Различение нескольких точек выхода в петлях» начинается с 15:50 и продолжается около трех минут. Вот основные моменты:

  • Конструкция for ... else была разработана Дональдом Кнутом в качестве замены для некоторых GOTO вариантов использования;
  • Повторное использование ключевого слова else имело смысл потому что «это то, что использовал Кнут, и люди знали, что в то время все [for заявления] включали if и GOTO внизу, и они ожидали else
  • В Оглядываясь назад, его следовало бы назвать «без перерыва» (или, возможно, «без перерыва»), и тогда это не могло бы сбить с толку. *

Итак, если возникает вопрос: «Почему бы не они меняют это ключевое слово? затем Cat Plus Plus, вероятно, дал самый точный ответ - на данный момент, это будет слишком разрушительным для существующего кода, чтобы быть практичным. Но если вопрос, который вы действительно задаете, заключается в том, почему else был повторно использован в первую очередь, ну, по-видимому, в то время это казалось хорошей идеей.

Лично мне нравится компромисс комментирования # no break в строке, где else можно было бы с первого взгляда ошибочно принять за принадлежность внутри цикла. Это достаточно ясно и кратко. Эта опция получает краткое упоминание в резюме, которое Бьорн связал в конце своего ответа:

Для полноты, я должен упомянуть, что с небольшим изменением синтаксиса программисты, которые хочу, чтобы этот синтаксис мог иметь его прямо сейчас:

for item in sequence:
    process(item)
else:  # no break
    suite

* Бонусная цитата из этой части видео: «Так же, как если бы мы назвали lambda makefunction, никто не спрашивал: «Что делает лямбда?»

144
ответ дан Community 28 November 2014 в 10:40
поделиться

Обычная конструкция - запускать цикл до тех пор, пока что-то не будет найдено, а затем вырваться из цикла. Проблема в том, что, если я выйду из цикла или завершу цикл, мне нужно определить, какой случай произошел. Один из способов - создать флаг или переменную хранилища, которая позволит мне выполнить второй тест, чтобы увидеть, как завершился цикл.

Например, предположим, что мне нужно искать в списке и обрабатывать каждый элемент, пока не будет найден элемент флага, а затем прекратить обработку. Если элемент флажка отсутствует, необходимо создать исключение.

Использование Python for ... else построить у вас есть

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

Сравните это с методом, который не использует этот синтаксический сахар:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

В первом случае raise тесно связан с циклом for it работает с. Во второй привязка не так сильна, и ошибки могут быть внесены во время обслуживания.

465
ответ дан Mateen Ulhaq 28 November 2014 в 10:40
поделиться

Я согласен, это больше похоже на 'elif not [условие (и), поднимающее разрыв]'.

Я знаю, что это старая ветка, но сейчас я изучаю тот же вопрос, и я не уверен, что кто-нибудь получил ответ на этот вопрос так, как я его понимаю.

Для меня есть три способа «чтения» else в For... else или While... else утверждениях, все из которых эквивалентны:

  1. else == if the loop completes normally (without a break or error)
  2. else == if the loop does not encounter a break
  3. else == else not (condition raising break) (предположительно, есть такое условие, иначе у вас не будет цикла )

Таким образом, по сути, «else» в цикле на самом деле является «elif ...» где «...» - это (1) без разрыва, что эквивалентно (2) НЕ [условие (и) подъема перерыва].

Я думаю, что ключ в том, что else бессмысленно без «разрыва», поэтому for...else включает в себя:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

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

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

Как говорили другие авторы, обычно возникает разрыв, когда вы можете найти то, что ищет ваша петля, поэтому else: становится «что делать, если целевой объект не найден».

Пример

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

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

Результат

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

Пример

Простой пример с ударом на разрыв.

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

Результат

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

Пример

Простой пример, где нет перерыва, нет условия, вызывающего перерыв, и нет встречаются ошибки.

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

Результат

z: 0
z: 1
z: 2
z_loop complete without break or error
----------
5
ответ дан NotAnAmbiTurner 28 November 2014 в 10:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: