Синтаксис функций и лямбда-выражений
Функции, декораторы и замыкания в Python: полное руководство
Python предлагает мощные инструменты для работы с функциями, декораторами и замыканиями. В этой статье мы разберем их синтаксис, применение и внутреннее устройство.
Синтаксис функций и лямбда-выражений
1. Объявление функций
Функции определяются через ключевое слово def:
def greet(name: str) -> str:
"""Возвращает приветствие."""
return f"Hello, {name}!"
- Параметры: позиционные (
name), именованные (name="User"),*args(список аргументов),**kwargs(словарь ключевых аргументов). - Типы: аннотации типов (
str) и->для возвращаемого значения.
2. Лямбда-функции
Анонимные функции задаются через lambda:
square = lambda x: x ** 2 # Эквивалентно def square(x): return x ** 2
print(square(3)) # 9
Ограничение: Лямбды могут содержать только одно выражение.
Области видимости переменных
- Локальные (local): Переменные внутри функции.
- Глобальные (global): Переменные уровня модуля.
- Нелокальные (nonlocal): Переменные из внешней функции (для вложенных функций).
- Enclosing: Область видимости внешней функции.
Пример:
x = "global"
def outer():
x = "outer"
def inner():
nonlocal x # Ссылается на x из outer()
x = "inner"
inner()
print(x) # "inner"
outer()
print(x) # "global"
Лямбды и функции высшего порядка
1. map, filter, zip
map: Применяет функцию к каждому элементу:numbers = [1, 2, 3] squared = list(map(lambda x: x ** 2, numbers)) # [1, 4, 9]filter: Фильтрует элементы:even = list(filter(lambda x: x % 2 == 0, numbers)) # [2]zip: Объединяет элементы итерируемых объектов:names = ["Alice", "Bob"] ages = [25, 30] combined = list(zip(names, ages)) # [("Alice", 25), ("Bob", 30)]
2. Функции как объекты первого класса
Функции можно:
- Присваивать переменным:
func = greet. - Передавать как аргументы:
def apply(func, arg): return func(arg). - Возвращать из других функций:
def multiplier(n): return lambda x: x * n double = multiplier(2)
Декораторы
1. Простой декоратор (без параметров)
Декоратор — функция, которая принимает другую функцию и возвращает новую:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logger
def calculate(a, b):
return a + b
calculate(3, 4) # Выводит: "Calling calculate", возвращает 7
2. Параметризованные декораторы
Требуют дополнительного уровня вложенности:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello")
say_hello() # Выводит "Hello" три раза
3. Время выполнения декораторов
Декораторы выполняются сразу после определения функции (при загрузке модуля).
4. Декораторы через классы
Используйте метод __call__:
class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
print(f"Time: {time.time() - start} sec")
return result
@Timer
def heavy_task():
time.sleep(2)
heavy_task() # Замеряет время выполнения
Замыкания (Closures)
1. Пример использования
Замыкание запоминает переменные из внешней области видимости:
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
c = counter()
print(c(), c(), c()) # 1, 2, 3
2. Внутреннее устройство
nonlocal: Позволяет изменять переменные из внешней функции.__closure__: Содержит ячейки с захваченными переменными.co_freevars: Имена захваченных переменных.cell_contents: Значение в ячейке.
def outer():
x = 10
def inner():
print(x)
return inner
func = outer()
print(func.__closure__[0].cell_contents) # 10
Метаинформация функций
- Документация:
__doc__для доступа к docstring. - Аннотации типов:
__annotations__хранит типы аргументов.def add(a: int, b: int) -> int: """Складывает два числа.""" return a + b print(add.__doc__) # "Складывает два числа." print(add.__annotations__) # {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
Рекомендации
- Декораторы: Используйте
functools.wrapsдля сохранения метаданных функции. - Замыкания: Избегайте цикловых зависимостей в захваченных переменных.
- Типизация: Аннотации упрощают чтение кода и проверку типов (например, через
mypy).
Заключение
Функции, декораторы и замыкания — ключевые элементы Python, позволяющие писать гибкий и выразительный код. Понимание их работы и внутренней механики открывает путь к созданию мощных абстракций и паттернов.