# Циклы. Работа со списками

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

## Перебор всего списка

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

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

{% hint style="info" %}
Например, в компьютерной игре все экранные объекты могут смещаться на одинаковую величину или в списке чисел к каждому элементу может применяться одна и та же статистическая операция. А может быть, вам потребовалось вывести все заголовки из списка статей на сайте.&#x20;
{% endhint %}

В ситуациях, требующих применения одного действия к каждому элементу списка, можно воспользоваться цикл `for`.

Допустим, имеется список студентов и вы хотите вывести каждое имя из списка. Конечно, можно обратиться к каждому элементу по отдельности, но такой подход создает ряд проблем. Во-первых, для очень длинных списков все сведется к однообразным повторениям. Во-вторых, при любом изменении длины списка в программу придется вносить изменения. Цикл `for` решает обе проблемы: Python будет следить за всеми техническими деталями в своей внутренней реализации.

В следующем примере цикл `for` используется для вывода имен студентов

```python
students = ['Иван', 'Петр', 'Сергей']

for name in students:
    print(name)
```

В строке 3 определяется цикл `for`. Эта строка говорит Python взять очередное имя из списка и сохранить его в переменной `name`. В строке 4 выводится имя, только что сохраненное в name. Затем строки 3 и 4 повторяются для каждого имени в списке. Этот код можно описать так: "Для каждого фокусника в списке вывести его имя". Результат представляет собой простой перечень имен из списка

```python
Иван
Петр
Сергей
```

### Подробнее о циклах

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

Например, в примере выше Python сначала читает первую строку цикла:

```python
for name in students:
```

Эта строка цикла означает, что нужно взять первое значение из списка `students`и сохранить его в переменной `name`. Первое значение в списке - `'Иван'`. Затем Python читает следующую строку:

```python
print(name)
```

Python выводит текущее значение `name`, которое равно `'Иван'`. Так как в списке еще остались другие значения, Python возвращается к первой строке цикла:

```python
for name in students:
```

Python берет следующее значение из списка - `'Петр'`, и сохраняет его в `students`. Затем выполняется строка:

```python
print(name)
```

Python снова выводит значение переменно `name`, теперь это `'Петр'`. Весь цикл повторяется еще раз с последним значением в списке - `'Сергей'`. Так как других значений в списке не осталось, Python переходит к следующей строке в программе. В данном случае после цикла `for` ничего нет, поэтому программа просто завершается.

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

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

```python
for dog in dogs:
    pass

for cat in cats:
    pass

for item in bundle:
    pass
```

Выполнение этого правила поможет вам проследить за тем, какие действия выполняются с каждым элементом в цикле `for`.

### Более сложные действия в циклах for

В цикле `for` с каждым элементом списка может выполняться практически любое действие

```python
```

Тело цикла `for` может содержать сколько угодно строк кода. Каждая строка с начальным отступом после строки `for name in students` считается находящейся в цикле и выполняется по одному разу для каждого значения в списке. Таким образом, с каждым значением в списке можно выполнить любые операции на ваше усмотрение. На практике часто требуется выполнить в цикле `for` несколько разных операций для каждого элемента списка.

### Выполнение действий после цикла for

Что происходит после завершения цикла `for`? Обычно программа выводит некую сводную информацию или переходит к другим операциям.

Каждая строка кода после цикла `for`, не имеющая отступа, выполняется без повторения.

```python
students = ['Иван', 'Петр', 'Сергей']

for name in students:
    print("Студент " + name)

print("Вы зачислены на бюджет")
```

Первая функция `print()` выполняется по одному разу для каждого элемента из списка студентов. Функция `print()` в строке 6 отступа не имеет, это сообщение выводится только один раз.

```python
Студент Иван
Студент Петр
Студент Сергей
Вы зачислены на бюджет
```

## Создание числовых списков

Необходимость хранения наборов чисел возникает в программах по многим причинам.

{% hint style="info" %}
Например, в компьютерной игре могут храниться координаты каждого персонажа на экране, таблицы рекордов и так далее. В программах визуализации данных пользователь почти всегда работает с наборами чисел: температурой, расстоянием, численностью населения, широтой\долготой и другими числовыми данными.
{% endhint %}

Списки идеально подходят для хранения наборов чисел, а Python предоставляет специальные средства для эффективной работы с числовыми списками. Достаточно один раз понять, как эффективно пользоваться этими средствами, и ваш код будет хорошо работать даже в том случае, если список содержит миллионы элементов.

### Функция range()

Функция `range()` упрощает построение числовых последовательностей. Например, с ее помощью можно легко вывести серию чисел:

```python
for value in range(1, 5):
    print(value)
```

И хотя на первый взгляд может показаться, что он должен вывести числа от `1` до `5`, на самом деле число `5` не выводится:

```python
1
2
3
4
```

В этом примере функция `range()` выводит только числа от `1` до `4`. Перед вами еще один пример явления "смещения на 1", которое часто встречается в языках программирования. При выполнении функции `range()` Python начинает отсчет от первого переданного значения и прекращает его при достижении второго. Так как на втором значении происходит остановка, конец интервала (в данном случае `5`) не встречается в выводе в консоль.

Чтобы вывести числа от `1` до `5`, используйте вызов `range(1, 6)`:

```python
for value in range(1, 6):
    print(value)
```

На этот раз вывод начинается с `1` и завершается `5`

```python
1
2
3
4
5
```

При вызове `range()` также можно передать только один аргумент. В этом случае последовательность чисел будет начинаться с `0`. Например, `range(6)` вернет числа от `0` до `5`.

```python
for value in range(6):
    print(value)
    
0
1
2
3
4
5
```

### Использование range() для создания числового списка

Если вы хотите создать числовой список, преобразуйте результаты `range()` в список с помощью функции `list()`. Если заключить вызов `range()` в `list()`, то результат будет представлять собой список с числовыми элементами.

```python
numbers = list(range(1,6))
print(numbers)

[1, 2, 3, 4, 5]
```

Функция `range()` также может генерировать числовые последовательности, пропуская числа в заданном диапазоне. Например, построение списка четных чисел от `1` до `10` происходит следующим образом

```python
numbers = list(range(1,11,2))
print(numbers)

[1, 3, 5, 7, 9]
```

В этом примере функция `range()` начинает со значения `2`, а затем увеличивает его на `2`. Приращение `2` последовательно применяется до тех пор, пока не будет достигнуто или пройдено конечное значение `11`, после чего выводится результат

```python
[2, 4, 6, 8, 10]
```

С помощью функции `range()` можно создать практически любой диапазон чисел. Например, как бы вы создали список квадратов всех целых чисел от `1` до `10`? Один из возможных вариантов выглядит так

```python
squares = []
for value in range(1, 11):
    squares.append(value ** 2)
    
print(squares)

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
```

### Некоторые функции работы со списками

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

```python
digits = [1, 2, 3, 4, 5]
print(min(digits))
print(max(digits))
print(sum(digits))

1
5
15
```

## Цикл while

While переводится с английского как "пока", в смысле "пока имеет это, делаем то".

Можно сказать, что `while` является универсальным циклом. Он присутствует во всех языках, поддерживающих структурное программирование, в том числе и в Python. Его синтаксис можно выразить так:

```python
while логическое_выражение:
    выражение 1;
    …
    выражение n;
```

Это похоже на условный оператор `if`. Однако в случае циклических операторов их тела могут выполняться многократно. В случае `if`, если логическое выражение в заголовке возвращает истину, то тело выполняется единожды. После этого поток выполнения программы возвращается в основную ветку и выполняет следующие выражения, расположенные ниже всей конструкции условного оператора.

В случае `while`, после того как его тело выполнено, поток возвращается к заголовку цикла и снова выполняет условие. Если логическое выражение возвращает истину, то тело снова выполняется. Потом снова возвращаемся к заголовку и так далее.

Цикл завершает свою работу только тогда, когда логическое выражение в заголовке возвращает ложь, то есть условие выполнения цикла больше не соблюдается. После этого поток выполнения перемещается к выражениям, расположенным ниже всего цикла. Говорят, что "происходит выход из цикла".

![](https://3745156914-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnmXmI-D1suCZkVT17D%2F-MJcYOwpRaem_YXy9cNa%2F-MJc_ktdKXiYEAUJ-en5%2Fimage.png?alt=media\&token=6ed2d1b1-70ad-434c-9ece-d934f97a7897)

С циклом `while` возможны две исключительные ситуации:

* если при первом заходе в цикл логическое выражение возвращает `False`, то тело цикла не выполняется ни разу. Эту ситуацию можно считать нормальной, так как при определенных условиях логика программы может предполагать отсутствие необходимости к выполнении выражений тела цикла;
* если логическое выражение в заголовке `while` никогда не возвращает `False`, а всегда остается равным `True`, то цикл никогда не завершится, если только в его теле нет оператора принудительного выхода из цикла (`break`) или вызовов функций выхода из программы - `quit()` или `exit()` в случае Python. Если цикл повторяется и повторяется бесконечное количество раз, то в программе происходит зацикливание (программа входит в бесконечный цикл) - программа не может завершится и бесконечно повторяет тело цикла.

Самое главное для цикла `while` - чтобы в его теле происходили изменения значений переменных, которые проверяются в его заголовке, и чтобы хоть когда-нибудь наступил случай, когда логическое выражение в заголовке возвращает `False`. Иначе произойдет зацикливание.

## Циклы с использованием счетчика цикла

Очень часто при использовании циклов и списков бывает необходимость изменить значения в списке или еще по каким-то причинам получить доступ к элементам списка через индекс.

Переменная, которая контролирует повторы выполнения циклов называется **счетчик цикла**.

```python
digits = [1, 2, 3, 4, 5]

print("Before: ", digits)

i = 0
for el in digits:
    digits[i] = el * 2
    i = i + 1
    
print("After: ", digits)

Before:  [1, 2, 3, 4, 5]
After:  [2, 4, 6, 8, 10]
```

Это не самая удобная конструкция для обращения к элементу цикла. Если мы знаем длину списка, мы можем использовать цикл `while`. Длину списка можно получить с помощью встроенной функции `len()`

```python
digits = [1, 2, 3, 4, 5]

print("Before: ", digits)

i = 0
while i < len(digits):
    digits[i] = digits[i] * 2
    i = i + 1

    
print("After: ", digits)

Before:  [1, 2, 3, 4, 5]
After:  [2, 4, 6, 8, 10]
```

### Использование range() и цикла for

Сочетание цикла `for` и функции `range()` позволяет сделать удобным доступ к элемента списка по индексу.

```python
digits = [1, 2, 3, 4, 5]

a = range(len(digits))
print(a)

range(0, 5)
```

С помощью функции len() измеряется длина списка. В данном случае она равна 5. После этого числа 5 передается в функцию range() и она генерирует последовательность чисел от 0 до 4 включительно. Это как раз индексы элементов нашего списка.

Используем этот принцип совместно с циклом for

```python
digits = [1, 2, 3, 4, 5]

print("Before: ", digits)

for i in range(len(digits)):
    digits[i] = digits[i] * 2
    
print("After: ", digits)

Before:  [1, 2, 3, 4, 5]
After:  [2, 4, 6, 8, 10]
```

### Функция enumerate()

В Python есть еще одна встроенная функция, которая часто используется в заголовке `for`. Это функция `enumerate()`. Если `range()` позволяет получить только индексы элементов списка, то enumerate() генерирует пары кортежей (кортеж - неизменяемый список, он будет рассмотрен позже).

```python
digits = [10, 20, 30, 40, 50]

print("Before: ", digits)

for i in enumerate(digits):
    digits[i[0]] = i[1] * 2
    print("Индекс: " + str(i[0]) + ", значение: " + str(i[1]))
    
print("After: ", digits)

Before:  [10, 20, 30, 40, 50]
Индекс: 0, значение: 10
Индекс: 1, значение: 20
Индекс: 2, значение: 30
Индекс: 3, значение: 40
Индекс: 4, значение: 50
After:  [20, 40, 60, 80, 100]
```

Чтобы не возиться с индексами, удобнее использовать следующую форму записи

```python
digits = [10, 20, 30, 40, 50]

print("Before: ", digits)

for index, value in enumerate(digits):
    digits[index] = value * 2
    print("Индекс: " + str(index) + ", значение: " + str(value))
    
print("After: ", digits)
```

## Операторы continue и break

Оператор `continue` позволяет перейти к следующей итерации цикла до завершения выполнения всех инструкций внутри цикла. В качестве примера, выведем на экран все нечетные числа в диапазоне от `0` до `20`

```python
for i in range(20):
    if i % 2 == 0:
        continue
    
    print(i)
```

Оператор `break` позволяет прервать выполнение цикла досрочно.

```python
# Выводим числа, пока не найдем число, которое
# делится на 7 без остатка
for i in range(1, 20):
    if i % 7 == 0:
        break
    
    print(i)
    
1
2
3
4
5
6
```

{% hint style="danger" %}
Внимание! Оператор `break` прерывает выполнение цикла, а не программы, то есть далее будет выполнена инструкция, следующая сразу за циклом
{% endhint %}

Цикл `while` совместно с оператором `break` удобно использовать для работы с вводом из консоли. К примеру, напишем небольшую программу, которая считывает числа, которые ввел пользователь. Для окончания ввода пользователь должен ввести `0`. После окончания ввода, программа выдает сумму введенных чисел.

```python
print("Программа суммирует введенные числа. Введите 0 для окончания ввода и"
       " получения суммы чисел")
sum = 0

while True:
    i = input("Введите число: ")
    i = int(i)
    
    if i == 0:
        break;
    
    sum = sum + i
    
print ("Сумма введенных чисел: ", sum)

Программа суммирует введенные числа. Введите 0 для окончания ввода
 и получения суммы чисел

Введите число: 10

Введите число: 20

Введите число: 30

Введите число: 0
Сумма введенных чисел:  60
```

