Как сделать «двойной break», то есть выйти из вложенного цикла, в Python?
58К открытий59К показов
Условие:
Перебрать все пары символов в строке, и остановиться при нахождении двух одинаковых символов.
Решение достаточно очевидное, но возникает вопрос:
Если бы мы программировали, например, на Java, то мы могли бы воспользоваться механизмом меток:
Однако в Python такого механизма нет. Требуется предложить наиболее удобное в использовании и читаемое решение.
Возможные варианты ответа
- Поместить цикл в тело функции, а затем сделать
return
из неё:def func():ts=”teste”tfor i in range(len(s)):ttfor j in range(i+1, len(s)):tttif s[i]==s[j]:ttttprint(i,j)ttttreturnfunc()Почему это плохая идея: разумеется, сама задача в условии — лишь абстрактный пример. В жизни циклов может быть гораздо больше, и создавать по функции для каждого из них как-то неестественно, не так ли? - Выбросить исключение и поймать его снаружи цикла:try:ts=”teste”tfor i in range(len(s)):ttfor j in range(i+1, len(s)):tttif s[i]==s[j]:ttttprint(i,j)ttttraise Exception()except:tprint(“the end”)Почему это плохая идея: здесь мы используем механизм исключений как особую форму goto, но ведь на самом деле ничего исключительного в коде не произошло — это обычная ситуация. Как минимум, причины такого злоупотребления этим механизмом будут непонятны другим программистам.
- Можно создать булевую переменную, которая будет хранить информацию о том, нужно ли выходить из внешнего цикла на данной итерации:exitFlag=Falses=”teste”for i in range(len(s)):tfor j in range(i+1, len(s)):ttif s[i]==s[j]:tttprint(i,j)tttexitFlag=Truetttbreaktif(exitFlag):ttbreakПочему это плохая идея: из всех перечисленных выше идей эта, пожалуй, лучшая. Тем не менее, это весьма низкоуровневый подход, и в языке Python есть возможность реализовать задуманное гораздо лучше.
- Использовать вместо двух циклов
for
одинwhile
:s=”teste”i=0j=1while i < len(s):tif s[i] == s[j]:ttprint(i, j)ttbreaktj=j+1ti=i+j//len(s)tj=j%len(s)Почему это плохая идея: вам не кажется, что такой код читается хуже всех предложенных вариантов?
Решение на пятёрку
Давайте ещё раз внимательно прочитаем условие:
Перебрать все пары символов в строке, и остановиться при нахождении двух одинаковых символов.
Где там вообще хоть слово про двойной цикл или про перебор двух индексов? Нам нужно перебирать пары. Значит, по идее, мы должны написать что-то вроде этого:
Отлично, так мы будем перебирать пары. Но как нам добиться именно такой формы записи? Всё очень просто, нужно создать генератор. Делается это следующим образом:
“Как это работает?” — спросите вы. Всё просто. При вызове unique_pairs(int)
код в теле функции не вычисляется. Вместо этого будет возвращён объект генератора. Каждый вызов метода next()
этого генератора (что неявно происходит при каждой итерации цикла for
) код в его теле будет выполняться до тех пор, пока не будет встречено ключевое слово yield
. После чего выполнение будет приостановлено, а метод вернёт указанный объект (здесь yield
действует подобно return). При следующем вызове функция начнёт выполняться не с начала, а с того места, на котором остановилась в прошлый раз. При окончании перебора будет выброшено исключение StopIteration
.
Итак, самый true pythonic way в решении этой задачи:
UPD: в комментариях подсказывают, что такой генератор уже реализован в стандартной библиотеке:
Что же, для данной задачи это действительно более pythonic решение. Хочется отметить, что целью статьи было скорее познакомить новичков с механизмом генераторов, нежели действительно решить проблему, заявленную в первом абзаце ?
Свои варианты предлагайте в комментариях!
58К открытий59К показов