Модуль 2: Управление потоком
В этом модуле вы изучите, как управлять потоком выполнения программы с использованием условных операторов, циклов и обработки исключений. Эти инструменты позволяют создавать гибкие и интеллектуальные программы, которые могут принимать решения и реагировать на различные условия.
2.1 Условные операторы
Что такое условные операторы?
Условные операторы позволяют программе выполнять разные блоки кода в зависимости от заданных условий. В Python основным условным оператором является if
.
Оператор if-elif-else
Конструкция if-elif-else позволяет проверить несколько условий последовательно:
age = 18
if age < 13:
print("Ребёнок")
elif age < 18:
print("Подросток")
else:
print("Взрослый")
# Результат: Взрослый
Важно: В Python для создания блоков кода используются отступы (обычно 4 пробела), а не фигурные скобки как во многих других языках.
Операторы сравнения
Для создания условий используются операторы сравнения:
Таблица операторов сравнения
Оператор | Описание | Пример |
---|---|---|
== | Равно | x == y |
!= | Не равно | x != y |
> | Больше чем | x > y |
< | Меньше чем | x < y |
>= | Больше или равно | x >= y |
<= | Меньше или равно | x <= y |
Логические операторы
Для объединения условий используются логические операторы:
# Оператор and (И): оба условия должны быть истинными
age = 25
income = 50000
if age > 21 and income > 30000:
print("Кредит одобрен")
# Оператор or (ИЛИ): хотя бы одно условие должно быть истинным
if age > 65 or income < 10000:
print("Предоставляется скидка")
# Оператор not (НЕ): инвертирует результат
is_weekend = False
if not is_weekend:
print("Рабочий день")
Тернарный оператор
Python поддерживает краткий способ записи условия в одну строку — тернарный оператор:
# Синтаксис: значение_если_истина if условие else значение_если_ложь
age = 20
status = "совершеннолетний" if age >= 18 else "несовершеннолетний"
print(status) # Результат: совершеннолетний
Проверка принадлежности и идентичности
Python предлагает специальные операторы для проверки принадлежности элемента к коллекции и идентичности объектов:
# Оператор in проверяет наличие элемента в последовательности
fruits = ["яблоко", "банан", "груша"]
if "банан" in fruits:
print("Банан в списке")
# Операторы is и is not проверяют, указывают ли переменные на один и тот же объект
a = [1, 2, 3]
b = a # b указывает на тот же список
c = [1, 2, 3] # c - новый список с такими же значениями
print(a is b) # True
print(a is c) # False
print(a == c) # True (содержимое равно)
Советы для практики
- Начинайте с простых условий и постепенно усложняйте их.
- Обращайте внимание на отступы — они определяют блоки кода в Python.
- Помните о приоритете операторов при создании сложных условий.
- Используйте скобки для группировки условий для лучшей читаемости.
Практическое задание
Напишите программу, которая запрашивает у пользователя его возраст и выводит соответствующее сообщение:
- Если возраст меньше 0, выведите "Ошибка: возраст не может быть отрицательным"
- Если возраст от 0 до 12, выведите "Ребенок"
- Если возраст от 13 до 17, выведите "Подросток"
- Если возраст от 18 до 64, выведите "Взрослый"
- Если возраст 65 и старше, выведите "Пенсионер"
Показать решение
age = int(input("Введите ваш возраст: "))
if age < 0:
print("Ошибка: возраст не может быть отрицательным")
elif age <= 12:
print("Ребенок")
elif age <= 17:
print("Подросток")
elif age <= 64:
print("Взрослый")
else:
print("Пенсионер")
2.2 Циклы (for/while)
Циклы позволяют выполнять один и тот же блок кода несколько раз. В Python есть два основных типа циклов: for
и while
.
Цикл for
Цикл for
используется для итерации по последовательностям (спискам, кортежам, строкам и т.д.) или другим итерируемым объектам.
# Базовый синтаксис цикла for
for элемент in последовательность:
# код, который выполняется для каждого элемента
# Пример: перебор элементов списка
fruits = ["яблоко", "банан", "груша"]
for fruit in fruits:
print(f"Я люблю {fruit}")
# Результат:
# Я люблю яблоко
# Я люблю банан
# Я люблю груша
Функция range()
Функция range()
часто используется с циклом for для создания последовательности чисел:
# range(stop) - числа от 0 до stop-1
for i in range(5):
print(i)
# Результат: 0 1 2 3 4
# range(start, stop) - числа от start до stop-1
for i in range(2, 6):
print(i)
# Результат: 2 3 4 5
# range(start, stop, step) - числа от start до stop-1 с шагом step
for i in range(1, 10, 2):
print(i)
# Результат: 1 3 5 7 9
Цикл while
Цикл while
выполняет блок кода, пока заданное условие остаётся истинным:
# Базовый синтаксис цикла while
while условие:
# код, который выполняется пока условие истинно
# Пример: счётчик с while
count = 0
while count < 5:
print(count)
count += 1 # увеличиваем счётчик
# Результат: 0 1 2 3 4
Предупреждение: Будьте осторожны с циклами while
! Если условие никогда не станет ложным, получится бесконечный цикл. Всегда проверяйте, что условие в какой-то момент изменится.
Управляющие операторы: break и continue
Python предоставляет специальные операторы для контроля выполнения циклов:
# break - немедленно прекращает выполнение цикла
for i in range(10):
if i == 5:
break # выход из цикла при i = 5
print(i)
# Результат: 0 1 2 3 4
# continue - пропускает текущую итерацию и переходит к следующей
for i in range(10):
if i % 2 == 0:
continue # пропускаем четные числа
print(i)
# Результат: 1 3 5 7 9
Цикл for-else и while-else
В Python циклы могут иметь блок else
, который выполняется после завершения цикла, если цикл не был прерван с помощью break
:
# Пример использования else с циклом for
for i in range(5):
print(i)
else:
print("Цикл завершен нормально")
# Результат: 0 1 2 3 4 Цикл завершен нормально
# Пример с прерыванием цикла
for i in range(5):
if i == 3:
break # прерываем цикл
print(i)
else:
print("Это сообщение не будет выведено")
# Результат: 0 1 2
Вложенные циклы
Циклы можно вкладывать друг в друга для обработки многомерных данных:
# Пример вложенных циклов: вывод таблицы умножения
for i in range(1, 4): # внешний цикл: строки
for j in range(1, 4): # внутренний цикл: столбцы
print(f"{i} × {j} = {i*j}", end="\t")
print() # переход на новую строку после каждой строки таблицы
# Результат:
# 1 × 1 = 1 1 × 2 = 2 1 × 3 = 3
# 2 × 1 = 2 2 × 2 = 4 2 × 3 = 6
# 3 × 1 = 3 3 × 2 = 6 3 × 3 = 9
Генераторы списков
Генераторы списков (list comprehensions) — это краткий и элегантный способ создания списков на основе существующих последовательностей:
# Синтаксис: [выражение for элемент in последовательность if условие]
# Создание списка квадратов чисел
numbers = [1, 2, 3, 4, 5]
squares = [x**2 for x in numbers]
print(squares) # [1, 4, 9, 16, 25]
# С условием: только четные числа
even_squares = [x**2 for x in numbers if x % 2 == 0]
print(even_squares) # [4, 16]
# Вложенные циклы в генераторе
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat_list = [x for row in matrix for x in row]
print(flat_list) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Когда использовать for, а когда while?
- Используйте for: когда заранее известно количество итераций или нужно перебрать все элементы последовательности.
- Используйте while: когда количество итераций заранее неизвестно и выполнение зависит от условия.
Советы для эффективной работы с циклами
- Избегайте изменения последовательности, по которой итерируется цикл for.
- Используйте функцию
enumerate()
для получения и индекса, и значения элемента:for index, value in enumerate(sequence):
- Для параллельной итерации по нескольким последовательностям применяйте
zip()
:for x, y in zip(list1, list2):
- Всегда проверяйте условие выхода из цикла while, чтобы избежать бесконечных циклов.
Практические задания
Задание 1: Напишите программу, которая выводит таблицу умножения для числа, введенного пользователем (от 1 до 10).
Показать решение
number = int(input("Введите число от 1 до 10: "))
print(f"Таблица умножения для числа {number}:")
for i in range(1, 11):
result = number * i
print(f"{number} × {i} = {result}")
Задание 2: Напишите программу, которая находит все числа от 1 до 100, которые делятся на 7, используя генератор списков.
Показать решение
divisible_by_7 = [num for num in range(1, 101) if num % 7 == 0]
print("Числа от 1 до 100, делящиеся на 7:")
print(divisible_by_7)
2.3 Исключения
Исключения — это объекты, которые представляют ошибки и особые ситуации, возникающие во время выполнения программы. В Python механизм обработки исключений позволяет корректно реагировать на ошибки, не прерывая работу программы.
Блок try-except
Основной конструкцией для обработки исключений является блок try-except
:
# Базовый синтаксис try-except
try:
# Код, который может вызвать исключение
result = 10 / 0 # Деление на ноль вызывает ZeroDivisionError
except ZeroDivisionError:
# Код, который выполняется при возникновении указанного исключения
print("Ошибка: деление на ноль!")
# Результат: Ошибка: деление на ноль!
Блок try-except-else-finally
Полная структура блока обработки исключений включает дополнительные секции else
и finally
:
try:
# Код, который может вызвать исключение
num = int(input("Введите число: "))
result = 100 / num
except ValueError:
# Выполняется при ошибке преобразования в int
print("Введено не число!")
except ZeroDivisionError:
# Выполняется при делении на ноль
print("Деление на ноль!")
else:
# Выполняется, если в блоке try не возникло исключений
print(f"Результат: {result}")
finally:
# Выполняется всегда, независимо от того, было ли исключение
print("Операция завершена")
Важно: Блок finally
выполняется всегда, вне зависимости от того, возникло исключение или нет. Это делает его идеальным местом для освобождения ресурсов (закрытие файлов, соединений с базой данных и т.д.).
Обработка нескольких исключений
Несколько типов исключений можно обрабатывать разными способами:
# Несколько блоков except для разных исключений
try:
value = int(input("Введите число: "))
result = 10 / value
except ValueError:
print("Некорректный ввод: не число")
except ZeroDivisionError:
print("Ошибка: деление на ноль")
# Несколько исключений в одном блоке except
try:
value = int(input("Введите число: "))
result = 10 / value
except (ValueError, ZeroDivisionError):
print("Произошла ошибка: неверный ввод или деление на ноль")
Перехват всех исключений
Python позволяет перехватывать все исключения, но этот подход следует использовать с осторожностью:
# Перехват любого исключения - избегайте такой практики в реальном коде!
try:
# Какой-то код
result = 10 / 0
except Exception as e:
# Получаем доступ к объекту исключения
print(f"Произошла ошибка: {e}")
# Результат: Произошла ошибка: division by zero
Предупреждение: Перехват всех исключений с помощью except Exception
или просто except:
может скрыть неожиданные ошибки и затруднить отладку. Лучше перехватывать только конкретные исключения, которые вы ожидаете и умеете обрабатывать.
Вызов исключений
Вы можете генерировать исключения самостоятельно с помощью оператора raise
:
# Генерация стандартного исключения
def validate_age(age):
if age < 0:
raise ValueError("Возраст не может быть отрицательным")
if age > 120:
raise ValueError("Недопустимый возраст")
return age
# Пример использования
try:
user_age = validate_age(-5)
except ValueError as error:
print(f"Ошибка: {error}")
# Результат: Ошибка: Возраст не может быть отрицательным
Создание собственных исключений
Вы можете создавать собственные классы исключений, наследуя их от базового класса Exception
:
# Определение пользовательского исключения
class InsufficientFundsError(Exception):
"""Вызывается при попытке снять больше денег, чем есть на счёте"""
pass
# Использование пользовательского исключения
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(f"Недостаточно средств. Баланс: {self.balance}, требуется: {amount}")
self.balance -= amount
return amount
# Пример использования
account = BankAccount(100)
try:
account.withdraw(150)
except InsufficientFundsError as e:
print(f"Ошибка: {e}")
Иерархия исключений
В Python все исключения организованы в иерархию. Вот некоторые из наиболее распространенных встроенных исключений:
Exception
: базовый класс для всех исключенийArithmeticError
: базовый класс для ошибок арифметикиZeroDivisionError
: деление на нольOverflowError
: результат вычисления слишком великValueError
: некорректное значениеTypeError
: операция с неподдерживаемым типомIndexError
: индекс вне диапазонаKeyError
: обращение к несуществующему ключу словаряFileNotFoundError
: файл не найденPermissionError
: недостаточно прав для выполнения операции
Лучшие практики обработки исключений
Практические советы
- Будьте конкретны: перехватывайте только те исключения, которые вы ожидаете и можете обработать.
- Минимизируйте блоки try: помещайте в try только тот код, который может вызвать исключение.
- Логируйте исключения: записывайте информацию об ошибках для последующего анализа.
- Не игнорируйте исключения: пустой блок
except:
может скрыть серьезные проблемы. - Используйте finally: для гарантированного освобождения ресурсов.
LBYL vs EAFP
В Python существуют два подхода к предотвращению ошибок:
- LBYL (Look Before You Leap) — "Смотри, прежде чем прыгать". Проверка условий перед выполнением операции.
- EAFP (Easier to Ask Forgiveness than Permission) — "Проще просить прощения, чем разрешения". Выполнение операции в блоке try-except.
# Подход LBYL (проверка перед действием)
def get_dict_value_lbyl(dictionary, key):
if key in dictionary:
return dictionary[key]
else:
return None
# Подход EAFP (обработка исключения)
def get_dict_value_eafp(dictionary, key):
try:
return dictionary[key]
except KeyError:
return None
В Python чаще предпочитают стиль EAFP, поскольку он часто делает код более читаемым и избегает гонок условий (race conditions).
Практическое задание
Напишите функцию safe_divide(a, b)
, которая безопасно делит a
на b
, обрабатывая возможные исключения:
- Если
b
равно 0, функция должна вернуть строку "Деление на ноль невозможно" - Если какой-либо из аргументов не является числом, функция должна вернуть "Ошибка: аргументы должны быть числами"
- В случае успешного деления функция возвращает результат операции
Показать решение
def safe_divide(a, b):
try:
# Проверяем, что аргументы - числа
result = float(a) / float(b)
return result
except ZeroDivisionError:
return "Деление на ноль невозможно"
except (ValueError, TypeError):
return "Ошибка: аргументы должны быть числами"
# Тестирование функции
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # Деление на ноль невозможно
print(safe_divide("10", "2")) # 5.0
print(safe_divide("abc", 2)) # Ошибка: аргументы должны быть числами
Поздравляем!
Вы прошли модуль "Управление потоком" в Python. Теперь вы знаете, как использовать условные операторы, циклы и обработку исключений для создания более сложной логики в своих программах!