Сообщить об ошибке.

Практические примеры for/in циклов, использование оператора else

Содержание:


Перебор ключей и значений словаря, используя for/in в Python.

При итерации по элементам словаря for/in, ключ и соответствующее значение могут быть получены одновременно с использованием метода словаря dict.items():

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
...
# gallahad the pure
# robin the brave

Смотрите материал "Сортировка словаря по значению и ключу в Python", чтобы перебрать его в отсортированном виде по ключам или значениям.

Варианты перебора списков, используя for/in в Python.

При итерации по последовательности с помощью инструкции for/in индекс позиции и соответствующее значение могут быть получены одновременно с помощью встроенной функции enumerate().

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
# 0 tic
# 1 tac
# 2 toe

Перебор значений нескольких списков одновременно.

Чтобы выполнить цикл над двумя или более последовательностями одновременно, списки могут быть соединены с помощью встроенной функции zip().

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}?  It is {1}.'.format(q, a))
...
# What is your name?  It is lancelot.
# What is your quest?  It is the holy grail.
# What is your favorite color?  It is blue.

Еще пример:

>>> lst1 = [0, 1, 2, 3, 4, 5]
>>> lst2 = [5, 3, 2, 0, 4, 1]
>>> lst3 = ['zero', 'one', 'two', 'three', 'four', 'five']
>>> for a, b, c in zip(lst1, lst2, lst3):
...     print(f'{c}:\t{a} + {b} = {a + b}')
...
# zero:   0 + 5 = 5
# one:    1 + 3 = 4
# two:    2 + 2 = 4
# three:  3 + 0 = 3
# four:   4 + 4 = 8
# five:   5 + 1 = 6

Перебор значений списка в обратном порядке.

Чтобы выполнить цикл над последовательностью в обратном направлении используйте встроенную функцию reversed().

>>> for i in reversed(range(1, 10, 2)):
...     print(i)
...
# 9
# 7
# 5
# 3
# 1

Перебор значений списка в отсортированном порядке.

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

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(basket):
...     print(f)
...
# apple
# banana
# orange
# pear

Изменение списка во время выполнения цикла.

Иногда возникает соблазн изменить список во время выполнения цикла. Не делайте этого, так как это может привести к непредсказуемым результатам. Зачастую проще и безопаснее создать список с новыми значениями, или по крайней мере изменяйте копию list.copy() исходного списка.

Пример, с созданием списка для новых значений.

>>> import math
# не изменяйте исходный список во время итерации
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
# создаем список для отобранных значений
>>> filtered_data = []
>>> for value in raw_data:
...     if not math.isnan(value):
...         filtered_data.append(value)
...
>>> filtered_data
# [56.2, 51.7, 55.3, 52.5, 47.8]

Использование оператора else в циклах for/in.

Оператор else в циклах for/in выполняется только если цикл закончился и не прервался оператором break. Звучит как то бессмысленно. Как можно использовать такое поведение?

Цикл for/in/else упрощает любой цикл, который использует логический флаг, подобный этому:

# флаг принятия дальнейшего решения
found = False   
for divisor in range(2, n):
    if n % divisor == 0:
        # если найден делитель, то меняем 
        # флаг на `True` и выходим из цикла
        found = True   
        break

# принимаем решение на основе значения флага
if found:
    print(n, 'is composite')
else:
    print(n, 'is prime')

Оператор else в for/in позволяет опустить флаг и сделать код выше компактнее:

for divisor in range(2, n):
    if n % divisor == 0:
        print(n, 'is composite')
        break
else:
    # else сработает, если цикл не завершиться
    # по `break`, т.е. преждевременно
    print(n, 'is prime')

Обратите внимание, что для кода, в котором принимается решение, что делать, уже есть естественное место для его выполнения (перед оператором break). Единственная новая функция здесь - это место для выполнения кода, когда не нашлось ни одного делителя divisor.

Такое поведение for/in/else работает только в сочетании с оператором break. Но все равно нужны логические значения (флаги), если например, ищется последнее совпадение или необходимо отслеживать несколько условий параллельно.

Если единственной целью цикла for/in является ответ да или нет (флаг принятия решения), то можно написать его намного короче с помощью встроенных функций any()/all() и выражение-генератор, которое дает логические значения:

if any(n % divisor == 0 for divisor in range(2, n)):
    print(n, 'is composite')
else:
    print(n, "is prime")

Этот код эффективен, как цикл с прерыванием, т.к. в функции any() происходит замыкание, а выражение-генератор выполняется только до тех пор, пока оно не вернет значение True. Этот код даже быстрее, чем цикл.