if/elif/else, for, while, break, continue, else в циклах, match/case (Python 3.10+)
Отступы — это синтаксис, а не стиль. 4 пробела — стандарт PEP 8. Смешение пробелов и табуляции вызывает
TabError.
x = 10
if x > 0:
print("positive")
elif x < 0:
print("negative")
else:
print("zero")Python приводит любой объект к bool через __bool__() или __len__().
# Ложные значения (falsy):
False, None, 0, 0.0, 0j # числа-нули
"", [], {}, set(), () # пустые коллекции
b"" # пустые байты
# Истинные значения (truthy): всё остальное
bool([]) # False
bool([0]) # True — список непустой, хотя содержит 0!
bool("") # False
bool("0") # True — строка непустая!
# Проверка на None — именно `is None`, не `== None`
if value is None:
handle_none()
if value is not None:
process(value)
# Проверка на пустоту — не `== []`, а просто `if`
if not my_list:
print("list is empty")
if my_list: # то же что len(my_list) > 0, но более Pythonic
process(my_list)# value_if_true if condition else value_if_false
status = "admin" if user.is_admin else "user"
message = f"{name} found" if name else "not found"
# Вложенный тернарный — избегайте, плохо читается
label = "high" if score > 80 else ("medium" if score > 50 else "low")
# Лучше if/elif/else явно:
if score > 80:
label = "high"
elif score > 50:
label = "medium"
else:
label = "low":= (Python 3.8+)Присваивание выражения (walrus operator) — присваивает и возвращает значение.
# Без моржика — дублирование:
data = compute()
if data:
process(data)
# С моржиком — компактно:
if data := compute():
process(data)
# Цикл чтения файла
with open("file.txt") as f:
while line := f.readline():
process(line.strip())
# Регулярные выражения — одновременно матч и проверка
import re
if m := re.search(r"(\d+)", text):
print(f"Found number: {m.group(1)}")
# List comprehension — вычислить один раз, использовать дважды
results = [y for x in data if (y := expensive(x)) > threshold]
# Когда НЕ использовать
x := 5 # SyntaxError — нужны скобки или контекст
(x := 5) # OK
y = (x := 5) # OK — x=5, y=5for# Итерация по любому iterable
for item in [1, 2, 3]:
print(item)
for char in "Python":
print(char)
for key in {"a": 1, "b": 2}:
print(key)
for key, value in {"a": 1, "b": 2}.items():
print(f"{key}={value}")range() — генератор числовых последовательностейrange(5) # 0, 1, 2, 3, 4
range(1, 6) # 1, 2, 3, 4, 5
range(0, 10, 2) # 0, 2, 4, 6, 8
range(10, 0, -1) # 10, 9, 8, ... 1
# range — ленивый: не хранит все числа в памяти
r = range(10**9)
print(r[500_000_000]) # мгновенно! — вычисляет по индексу
print(len(r)) # 1_000_000_000
print(7 in r) # O(1) — не перебирает все числаenumerate() — индекс + элементfruits = ["apple", "banana", "cherry"]
# ❌ Антипаттерн: ручной счётчик
i = 0
for fruit in fruits:
print(f"{i}: {fruit}")
i += 1
# ✅ enumerate
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# С нестандартным стартом
for i, fruit in enumerate(fruits, start=1):
print(f"{i}: {fruit}") # 1: apple, 2: banana, ...zip() — параллельная итерацияnames = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 73]
grades = ["A", "B", "C"]
# Остановится на самом коротком итераторе
for name, score in zip(names, scores):
print(f"{name}: {score}")
# zip возвращает кортежи — можно распаковать
pairs = list(zip(names, scores)) # [("Alice", 95), ("Bob", 87), ...]
# Создать словарь
mapping = dict(zip(names, scores)) # {"Alice": 95, "Bob": 87, ...}
# zip с *iterables — "распаковка" (unzip)
pairs = [(1, "a"), (2, "b"), (3, "c")]
nums, chars = zip(*pairs) # (1, 2, 3), ("a", "b", "c")
# zip_longest — заполняет None (или fillvalue) для коротких
from itertools import zip_longest
for a, b in zip_longest([1, 2, 3], ["a", "b"], fillvalue=None):
print(a, b)
# 1 a
# 2 b
# 3 Nonewhile# Классический цикл с условием
counter = 0
while counter < 5:
print(counter)
counter += 1
# Бесконечный цикл с выходом по условию
while True:
data = fetch_next()
if data is None:
break
process(data)
# Читаем пока не получим валидный ввод
while not (name := input("Enter name: ").strip()):
print("Name cannot be empty!")break, continue, pass# break — выход из цикла
for n in range(10):
if n == 5:
break # выйдет из for
print(n) # 0, 1, 2, 3, 4
# continue — пропустить итерацию
for n in range(10):
if n % 2 == 0:
continue # пропустить чётные
print(n) # 1, 3, 5, 7, 9
# pass — заглушка (ничего не делает)
for n in range(10):
pass # пустой цикл, корректный синтаксис
class AbstractBase:
def method(self):
pass # будет реализован в подклассах
# ... (Ellipsis) — ещё одна заглушка
class Protocol:
def method(self) -> None: ... # типичный паттерн для Protocol/ABCelse в циклахСекция else выполняется только если цикл завершился без break.
# Поиск простого числа
def is_prime(n: int) -> bool:
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False # нашли делитель — не простое
else:
return True # цикл завершился без break — простое
# Поиск элемента
def find_first(lst, predicate):
for item in lst:
if predicate(item):
break
else:
raise ValueError("No matching element found")
return item
# while-else: редко используется
attempts = 0
while attempts < 3:
if try_operation():
break
attempts += 1
else:
raise RuntimeError("All attempts failed")# [expression for item in iterable if condition]
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
words_upper = [w.upper() for w in ["hello", "world"]]
# Вложенные comprehensions
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
# Flatten матрицы
flat = [x for row in matrix for x in row]
# [1, 2, 3, 2, 4, 6, 3, 6, 9]
# Несколько условий
filtered = [x for x in range(100) if x % 2 == 0 if x % 3 == 0]
# Числа делящиеся на 2 И на 3# Dict comprehension
names = ["alice", "bob", "charlie"]
name_lengths = {name: len(name) for name in names}
# {"alice": 5, "bob": 3, "charlie": 7}
# Инвертировать словарь
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
# Фильтрация
admins = {id: user for id, user in users.items() if user["role"] == "admin"}
# Set comprehension
unique_lengths = {len(word) for word in words}# Ленивый — не создаёт список в памяти
gen = (x**2 for x in range(1_000_000)) # мгновенно
total = sum(gen) # вычисляется по одному элементу
# Передача в функцию — можно без лишних скобок
total = sum(x**2 for x in range(1000))
any_large = any(x > 999 for x in data)
all_positive = all(x > 0 for x in numbers)
result = max(len(line) for line in lines)
# Разница в памяти
import sys
lst = [x**2 for x in range(1000)]
gen = (x**2 for x in range(1000))
print(sys.getsizeof(lst)) # ~8856 bytes
print(sys.getsizeof(gen)) # ~208 bytesmatch / case (Python 3.10+)Structural Pattern Matching — мощнее switch/case из других языков.
def describe(x):
match x:
case 0:
return "zero"
case 1 | 2 | 3: # OR — несколько значений
return "small positive"
case int(n) if n > 100: # guard condition
return f"large: {n}"
case int():
return "some integer"
case str(s):
return f"string: {s}"
case _: # wildcard — always matches
return "other"def parse_command(cmd):
match cmd.split():
case ["quit"]:
return "exit"
case ["go", direction]:
return f"move {direction}"
case ["go", direction, speed]:
return f"move {direction} at {speed}"
case ["get", obj, *rest]: # *rest захватывает остаток
return f"get {obj}, extras: {rest}"
case _:
return "unknown command"
parse_command("go north") # "move north"
parse_command("get sword shield") # "get sword, extras: ['shield']"def process_event(event):
match event:
case {"type": "click", "x": x, "y": y}:
return f"Click at ({x}, {y})"
case {"type": "keypress", "key": key}:
return f"Key: {key}"
case {"type": str(t)}:
return f"Unknown event type: {t}"
# Паттерн класса
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
def classify_point(point):
match point:
case Point(x=0, y=0):
return "origin"
case Point(x=0, y=y):
return f"on Y-axis at {y}"
case Point(x=x, y=0):
return f"on X-axis at {x}"
case Point(x=x, y=y) if x == y:
return f"on diagonal at {x}"
case Point(x=x, y=y):
return f"({x}, {y})"
# Вложенные паттерны
def process(data):
match data:
case {"users": [{"name": str(name), "role": "admin"}, *rest]}:
return f"First admin: {name}, others: {len(rest)}"
case {"users": []}:
return "no users"__match_args__ для позиционного сопоставления@dataclass
class Color:
r: int
g: int
b: int
# dataclass автоматически устанавливает __match_args__ = ("r", "g", "b")
def classify_color(c):
match c:
case Color(0, 0, 0): # позиционно: r=0, g=0, b=0
return "black"
case Color(255, 255, 255):
return "white"
case Color(r, 0, 0): # красный с любым r
return f"red shade: {r}"# ❌ Глубокая вложенность ("pyramid of doom")
def process_user(user):
if user is not None:
if user.is_active:
if user.has_permission("admin"):
if user.quota > 0:
do_work(user)
return True
return False
# ✅ Early return — плоская структура
def process_user(user):
if user is None:
return False
if not user.is_active:
return False
if not user.has_permission("admin"):
return False
if user.quota <= 0:
return False
do_work(user)
return Truedef calculate_discount(user, purchase_amount):
# Guard clauses проверяют условия в начале
if not user:
raise ValueError("User required")
if purchase_amount <= 0:
raise ValueError("Amount must be positive")
if not user.is_premium:
return 0 # no discount for regular users
# Основная логика только для валидных случаев
if purchase_amount > 10000:
return 0.15
elif purchase_amount > 5000:
return 0.10
else:
return 0.05for/while как State Machinefrom enum import Enum, auto
class State(Enum):
IDLE = auto()
PROCESSING = auto()
DONE = auto()
ERROR = auto()
def run_state_machine(items):
state = State.IDLE
results = []
for item in items:
match state:
case State.IDLE:
if item:
state = State.PROCESSING
case State.PROCESSING:
try:
results.append(process(item))
except Exception:
state = State.ERROR
break
if not item:
state = State.DONE
case _:
break
return results, state# Любой объект с __iter__ — итерируемый (iterable)
# Объект с __iter__ И __next__ — итератор
# for реализует протокол:
for x in iterable:
process(x)
# Эквивалентно:
iterator = iter(iterable) # вызывает iterable.__iter__()
while True:
try:
x = next(iterator) # вызывает iterator.__next__()
process(x)
except StopIteration:
break
# Ручное управление итератором
it = iter([1, 2, 3])
print(next(it)) # 1
print(next(it)) # 2
print(next(it, "default")) # 3
print(next(it, "default")) # "default" — вместо StopIterationis_prime(n) используя for/else без флаговой переменной.chunk(iterable, size) делящую итерируемое на части размером size.match, напишите парсер простых математических выражений вида ["add", 1, 2], ["mul", 3, 4], ["div", 10, ["add", 1, 1]].while True: ... break vs while condition: .... Когда лучше использовать каждый подход?flatten(nested) — рекурсивное разворачивание вложенных списков используя генераторы.Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.