Перейти к содержимому

7. Функции

Иллюстрация к уроку

# Базовый синтаксис
def greet(name: str) -> str:
"""Возвращает приветствие."""
return f"Hello, {name}!"
result = greet("Яша") # "Hello, Яша!"

Python очень гибкий в работе с параметрами:

# Обязательные параметры
def add(a: int, b: int) -> int:
return a + b
# Параметры по умолчанию
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
greet("Яша") # "Hello, Яша!"
greet("Яша", "Привет") # "Привет, Яша!"
# Именованные аргументы (keyword arguments)
def create_user(name: str, age: int, role: str = "user"):
return {"name": name, "age": age, "role": role}
# Вызов с именованными аргументами (порядок не важен!)
user = create_user(age=25, name="Яша", role="admin")
# *args — произвольное количество позиционных аргументов
def sum_all(*args: int) -> int:
return sum(args)
sum_all(1, 2, 3, 4, 5) # 15
# **kwargs — произвольное количество именованных аргументов
def create_profile(**kwargs) -> dict:
return kwargs
create_profile(name="Яша", age=2, city="Москва")
# {"name": "Яша", "age": 2, "city": "Москва"}
# Всё вместе
def mixed(required, *args, default="нет", **kwargs):
print(f"required: {required}")
print(f"args: {args}")
print(f"default: {default}")
print(f"kwargs: {kwargs}")
from typing import Optional, Union, Any
# Optional — значение или None
def find_user(id: int) -> Optional[dict]:
# может вернуть dict или None
...
# Union — один из типов
def process(value: Union[int, str]) -> str:
return str(value)
# Python 3.10+: используй | вместо Union
def process(value: int | str) -> str:
return str(value)
# Коллекции
def get_names(users: list[dict]) -> list[str]:
return [u["name"] for u in users]
def get_config() -> dict[str, Any]:
return {"debug": True, "port": 8000}
# lambda: маленькие анонимные функции
square = lambda x: x ** 2
add = lambda a, b: a + b
# Основное использование — в качестве аргумента
users = [
{"name": "Вера", "age": 30},
{"name": "Анна", "age": 25},
{"name": "Гена", "age": 22},
]
# Сортировка по возрасту
sorted_users = sorted(users, key=lambda u: u["age"])
# Сортировка по имени, по убыванию
sorted_by_name_desc = sorted(users, key=lambda u: u["name"], reverse=True)
# filter, map, reduce
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
# [2, 4, 6, 8, 10]
doubled = list(map(lambda x: x * 2, numbers))
# [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Но comprehensions читаемее!
evens = [x for x in numbers if x % 2 == 0]
doubled = [x * 2 for x in numbers]

Декораторы — функции, которые оборачивают другие функции. Широко используются в FastAPI и Django!

# Простой декоратор
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Вызов: {func.__name__}")
result = func(*args, **kwargs)
print(f"Результат: {result}")
return result
return wrapper
@log_call
def add(a, b):
return a + b
add(2, 3)
# Вызов: add
# Результат: 5
# Декоратор с параметрами
def repeat(n: int):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def hello(name: str):
print(f"Hello, {name}!")
hello("Яша") # Выведет 3 раза
# functools.wraps — сохраняет метаданные функции
from functools import wraps
def timer(func):
import time
@wraps(func) # важно!
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} выполнялась {end - start:.3f}с")
return result
return wrapper
@timer
def slow_function():
import time
time.sleep(1)
return "готово"
def make_counter(start: int = 0):
count = start
def increment(step: int = 1):
nonlocal count # обращение к внешней переменной
count += step
return count
return increment
counter = make_counter(10)
counter() # 11
counter() # 12
counter(5) # 17
# Практический пример: фабрика функций
def make_multiplier(factor: int):
return lambda x: x * factor
double = make_multiplier(2)
triple = make_multiplier(3)
double(5) # 10
triple(5) # 15
# Генератор — функция с yield, возвращает значения лениво
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
for _ in range(10):
print(next(fib)) # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
# Генераторное выражение (как list comprehension, но ленивое)
big_sum = sum(x**2 for x in range(1_000_000)) # не хранит всё в памяти
# Практический пример: чтение большого файла
def read_chunks(filename: str, chunk_size: int = 1024):
with open(filename) as f:
while chunk := f.read(chunk_size):
yield chunk
# Утилиты для работы с данными
from typing import TypeVar, Callable, Iterable
T = TypeVar("T")
def first(items: Iterable[T], predicate: Callable[[T], bool]) -> T | None:
"""Найти первый элемент, удовлетворяющий условию."""
return next((item for item in items if predicate(item)), None)
users = [{"name": "Анна", "role": "admin"}, {"name": "Борис", "role": "user"}]
admin = first(users, lambda u: u["role"] == "admin")
# {"name": "Анна", "role": "admin"}
def group_by(items: list[T], key: Callable[[T], str]) -> dict[str, list[T]]:
"""Сгруппировать элементы по ключу."""
result: dict[str, list[T]] = {}
for item in items:
k = key(item)
result.setdefault(k, []).append(item)
return result
by_role = group_by(users, lambda u: u["role"])
# {"admin": [{"name": "Анна", ...}], "user": [{"name": "Борис", ...}]}
# Задание 1: Декоратор кэширования
# Напиши декоратор @cache, который сохраняет результаты функции
# и при повторном вызове с теми же аргументами возвращает из кэша
# Задание 2: Функция пагинации
def paginate(items: list, page: int, page_size: int) -> dict:
"""
Возвращает страницу данных.
Returns: {"items": [...], "total": int, "page": int, "pages": int}
"""
pass # реализуй!
# Задание 3: Генератор уникальных ID
def id_generator(prefix: str = "id"):
"""Бесконечный генератор уникальных ID: id-1, id-2, id-3, ..."""
pass # реализуй!

В следующем уроке — списки, словари и кортежи в деталях!