Управляющие конструкции определяют порядок выполнения инструкций. Python предлагает классические условия и циклы, а также мощный structural pattern matching (match/case), появившийся в Python 3.10.
Условные конструкции: if / elif / else
age = 25
if age < 18:
print("Несовершеннолетний")
elif age < 65:
print("Взрослый")
else:
print("Пенсионер")
# Single-line (only for simple cases)
status = "активен" if age >= 18 else "неактивен"
# Multiple conditions
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"Оценка: {grade}") # Оценка: B
Условные выражения (тернарный оператор)
# Conditional expression (ternary)
x = 10
result = "положительное" if x > 0 else "отрицательное или ноль"
# Chained (avoid - hard to read)
y = 0
sign = "+" if y > 0 else "-" if y < 0 else "0"
# With walrus operator
data = [1, 2, 3, 4, 5]
if (n := len(data)) > 3:
print(f"Много данных: {n} элементов")
Structural Pattern Matching (match/case)
Мощная конструкция, появившаяся в Python 3.10. Это не просто switch/case -- это полноценное сопоставление с образцом:
# Basic value matching
def http_status(code: int) -> str:
match code:
case 200:
return "OK"
case 301:
return "Moved Permanently"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return f"Unknown status: {code}"
print(http_status(404)) # Not Found
Сопоставление с захватом переменных
# Pattern matching with variable capture
def process_command(command: str) -> str:
match command.split():
case ["quit"]:
return "Выход"
case ["hello", name]:
return f"Привет, {name}!"
case ["move", x, y]:
return f"Перемещение в ({x}, {y})"
case ["move", x, y, z]:
return f"Перемещение в ({x}, {y}, {z})"
case _:
return "Неизвестная команда"
print(process_command("hello Иван")) # Привет, Иван!
print(process_command("move 10 20")) # Перемещение в (10, 20)
print(process_command("move 1 2 3")) # Перемещение в (1, 2, 3)
Сопоставление со структурами данных
# Matching dictionaries and nested structures
def process_event(event: dict) -> str:
match event:
case {"type": "click", "x": x, "y": y}:
return f"Клик в ({x}, {y})"
case {"type": "keypress", "key": key}:
return f"Нажата клавиша: {key}"
case {"type": "scroll", "direction": "up" | "down" as d}:
return f"Прокрутка: {d}"
case _:
return "Неизвестное событие"
print(process_event({"type": "click", "x": 100, "y": 200}))
# Клик в (100, 200)
print(process_event({"type": "scroll", "direction": "up"}))
# Прокрутка: up
Guards (условия в паттернах)
# Pattern matching with guards
def classify_point(point: tuple[int, int]) -> str:
match point:
case (0, 0):
return "Начало координат"
case (x, 0):
return f"На оси X: x={x}"
case (0, y):
return f"На оси Y: y={y}"
case (x, y) if x == y:
return f"На диагонали: ({x}, {y})"
case (x, y) if x > 0 and y > 0:
return f"Первый квадрант: ({x}, {y})"
case (x, y):
return f"Точка ({x}, {y})"
print(classify_point((5, 5))) # На диагонали: (5, 5)
print(classify_point((3, 0))) # На оси X: x=3
Сопоставление с классами
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
@dataclass
class Circle:
center: Point
radius: float
@dataclass
class Rectangle:
top_left: Point
bottom_right: Point
def describe_shape(shape) -> str:
match shape:
case Circle(center=Point(x=0, y=0), radius=r):
return f"Круг в центре координат, радиус {r}"
case Circle(radius=r) if r > 100:
return f"Большой круг радиусом {r}"
case Circle(center=c, radius=r):
return f"Круг в ({c.x}, {c.y}), радиус {r}"
case Rectangle(top_left=tl, bottom_right=br):
w = br.x - tl.x
h = br.y - tl.y
return f"Прямоугольник {w}x{h}"
case _:
return "Неизвестная фигура"
print(describe_shape(Circle(Point(0, 0), 5)))
# Круг в центре координат, радиус 5
Цикл for
Python for итерирует по любому итерируемому объекту:
# Iterate over a list
fruits = ["яблоко", "банан", "вишня"]
for fruit in fruits:
print(fruit)
# Iterate over a string
for char in "Python":
print(char, end=" ") # P y t h o n
# Iterate over a dictionary
config = {"host": "localhost", "port": 8080, "debug": True}
for key in config:
print(f"{key} = {config[key]}")
# Better: iterate over items
for key, value in config.items():
print(f"{key} = {value}")
# Iterate over keys or values
for key in config.keys():
print(key)
for value in config.values():
print(value)
range()
# range(stop) - from 0 to stop-1
for i in range(5):
print(i, end=" ") # 0 1 2 3 4
# range(start, stop)
for i in range(2, 7):
print(i, end=" ") # 2 3 4 5 6
# range(start, stop, step)
for i in range(0, 20, 3):
print(i, end=" ") # 0 3 6 9 12 15 18
# Counting down
for i in range(10, 0, -1):
print(i, end=" ") # 10 9 8 7 6 5 4 3 2 1
# range is lazy - doesn't create a list in memory
r = range(1_000_000_000) # uses almost no memory
print(999_999 in r) # True (O(1) check)
print(len(r)) # 1000000000
enumerate()
# enumerate() adds an index counter
languages = ["Python", "JavaScript", "Go", "Rust"]
for index, lang in enumerate(languages):
print(f"{index}: {lang}")
# 0: Python
# 1: JavaScript
# 2: Go
# 3: Rust
# Custom start index
for num, lang in enumerate(languages, start=1):
print(f"{num}. {lang}")
# 1. Python
# 2. JavaScript
# 3. Go
# 4. Rust
zip() -- параллельная итерация
# Iterate over multiple sequences in parallel
names = ["Иван", "Мария", "Алексей"]
ages = [25, 30, 28]
cities = ["Москва", "Петербург", "Казань"]
for name, age, city in zip(names, ages, cities):
print(f"{name}, {age} лет, {city}")
# zip stops at the shortest sequence
short = [1, 2]
long = [10, 20, 30, 40]
print(list(zip(short, long))) # [(1, 10), (2, 20)]
# Use zip_longest to pad with None
from itertools import zip_longest
print(list(zip_longest(short, long, fillvalue=0)))
# [(1, 10), (2, 20), (0, 30), (0, 40)]
# Strict mode (Python 3.10+) - error if lengths differ
# list(zip(short, long, strict=True)) # ValueError!
Цикл while
# Basic while loop
count = 5
while count > 0:
print(count, end=" ")
count -= 1
# 5 4 3 2 1
# While with condition
password = ""
while password != "секрет":
password = input("Введите пароль: ")
print("Доступ разрешён!")
# Infinite loop with break
while True:
line = input(">>> ")
if line == "quit":
break
print(f"Вы ввели: {line}")
break, continue, else
# break - exit the loop immediately
for n in range(2, 100):
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
break
else:
# else runs if loop completed WITHOUT break
print(n, end=" ")
# Prints all prime numbers up to 99
# continue - skip to the next iteration
for i in range(10):
if i % 3 == 0:
continue # skip multiples of 3
print(i, end=" ")
# 1 2 4 5 7 8
# for...else example
def find_item(items: list, target: str) -> int:
"""Find target in items, return index or -1."""
for i, item in enumerate(items):
if item == target:
print(f"Найдено: {target} на позиции {i}")
break
else:
# Executed only if loop finished without break
print(f"{target} не найдено")
return -1
return i
find_item(["a", "b", "c"], "b") # Найдено: b на позиции 1
find_item(["a", "b", "c"], "z") # z не найдено
while...else
# while...else - else runs when condition becomes False
n = 10
while n > 0:
if n == 5:
print("Прервано на 5")
break
n -= 1
else:
# This would run if while condition became False naturally
print("Цикл завершён нормально")
# Here: "Прервано на 5" (else block skipped because of break)
Вложенные циклы и итерация
# Nested loops
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
for row in matrix:
for cell in row:
print(f"{cell:3}", end="")
print()
# 1 2 3
# 4 5 6
# 7 8 9
# Flat iteration with itertools
from itertools import chain
flat = list(chain.from_iterable(matrix))
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Product of iterables (replaces nested loops)
from itertools import product
for x, y in product(range(3), range(3)):
print(f"({x},{y})", end=" ")
# (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2)
Практические паттерны
Обработка данных
# Filter and transform
scores = [85, 92, 45, 78, 95, 60, 88, 55]
# Find passing scores
passing = [s for s in scores if s >= 70]
print(f"Сдали: {passing}") # [85, 92, 78, 95, 88]
# Calculate average
average = sum(scores) / len(scores)
print(f"Средний балл: {average:.1f}") # 74.8
# Find max with index
max_score = max(scores)
max_idx = scores.index(max_score)
print(f"Лучший результат: {max_score} (позиция {max_idx})")
Retry-паттерн
import time
def fetch_with_retry(url: str, max_retries: int = 3) -> str:
"""Fetch URL with exponential backoff retry."""
for attempt in range(max_retries):
try:
# Simulated fetch
if attempt < 2:
raise ConnectionError("Timeout")
return f"Data from {url}"
except ConnectionError as e:
wait = 2 ** attempt # exponential backoff
print(f"Попытка {attempt + 1} неудачна: {e}. Ждём {wait}с...")
time.sleep(wait)
else:
raise ConnectionError(f"Не удалось подключиться после {max_retries} попыток")
# result = fetch_with_retry("https://api.example.com/data")
Меню с match/case
def calculator():
"""Simple calculator using match/case."""
while True:
expr = input("Введите выражение (или 'q' для выхода): ")
match expr.split():
case ["q"]:
print("До свидания!")
break
case [a, "+", b]:
print(f"= {float(a) + float(b)}")
case [a, "-", b]:
print(f"= {float(a) - float(b)}")
case [a, "*", b]:
print(f"= {float(a) * float(b)}")
case [a, "/", b] if float(b) != 0:
print(f"= {float(a) / float(b)}")
case [_, "/", "0"]:
print("Ошибка: деление на ноль!")
case _:
print("Неверный формат. Используйте: число оператор число")
Итоги
- if/elif/else -- базовые условия, поддерживают тернарный оператор
- match/case -- мощное сопоставление с образцом (паттерны, guards, захват переменных)
- for -- итерация по любому итерируемому объекту
- while -- цикл с условием,
while True+breakдля бесконечных циклов - range() -- ленивая последовательность чисел
- enumerate() -- добавляет счётчик к итерации
- zip() -- параллельная итерация
- break/continue -- управление потоком внутри цикла
- for...else -- блок else выполняется только если цикл не был прерван