Декораторы в Python
Эта статья объясняет декораторы в Python.
YouTube Video
Декораторы в Python
Декораторы в Python — это мощная функция, используемая для добавления дополнительной функциональности функциям или методам. Декораторы позволяют добавлять новую функциональность без изменения существующего кода, что повышает его повторное использование и поддерживаемость.
Основы декораторов
Декораторы в Python работают, принимая функцию в качестве аргумента и возвращая новую функцию с добавленной функциональностью. С помощью декораторов можно легко добавить предварительную или последующую обработку к функциям.
Без декораторов изменение поведения функции требует прямого редактирования самой функции. С декораторами вы можете расширить функциональность, не изменяя оригинальную реализацию.
Основная структура декоратора
1def my_decorator(func):
2 def wrapper():
3 print("Before the function call")
4 func()
5 print("After the function call")
6 return wrapper
7
8@my_decorator
9def say_hello():
10 print("Hello!")
11
12say_hello()
В этом примере функция my_decorator
используется как декоратор, оборачивающий функцию say_hello
. Декоратор применяется с помощью синтаксиса @my_decorator
, и когда вызывается say_hello()
, пред- и пост-обработка, предоставляемая декоратором, выполняется автоматически.
Как работают декораторы
Декораторы работают следующим образом.
-
Декоратор принимает функцию (или метод) в качестве аргумента.
-
Он определяет функцию-обертку для выполнения исходной функции.
-
Функция-обертка выполняет дополнительную обработку до или после выполнения исходной функции.
-
Декоратор возвращает функцию-обертку. В результате исходная функция заменяется новой, декорированной функцией.
Декораторы для функций с аргументами
При применении декоратора к функции с аргументами функцию-обертку необходимо настроить для приема этих аргументов.
1def my_decorator(func):
2 def wrapper(*args, **kwargs):
3 print("Before the function call")
4 result = func(*args, **kwargs)
5 print("After the function call")
6 return result
7 return wrapper
8
9@my_decorator
10def greet(name):
11 print(f"Hello, {name}!")
12
13greet("Alice")
Используя *args
и **kwargs
, можно обрабатывать функции, принимающие любое количество аргументов и именованных аргументов. Это позволяет применять декораторы универсально к функциям с любым типом аргументов.
Примеры применения декораторов
Декоратор для логгирования
Декораторы часто используются для добавления функциональности логгирования. Например, создав декоратор, который логгирует до и после выполнения функции, вы можете записывать, когда функция вызывается и сколько времени занимает её выполнение.
1import time
2
3def log_time(func):
4 def wrapper(*args, **kwargs):
5 start_time = time.time()
6 print(f"Calling function '{func.__name__}'...")
7 result = func(*args, **kwargs)
8 end_time = time.time()
9 print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10 return result
11 return wrapper
12
13@log_time
14def long_task(duration):
15 time.sleep(duration)
16 print("Task completed!")
17
18long_task(2)
В этом примере декоратор log_time
измеряет время выполнения функции и выводит его в виде лога. Функция long_task
обернута декоратором, и время её выполнения фиксируется во время выполнения программы.
Декоратор для управления правами доступа
Декораторы также могут использоваться для управления правами доступа. Например, вы можете ограничить выполнение процесса, проверяя, обладает ли пользователь определёнными правами доступа.
1def requires_permission(user_role):
2 def decorator(func):
3 def wrapper(*args, **kwargs):
4 if user_role != "admin":
5 print("Permission denied!")
6 return
7 return func(*args, **kwargs)
8 return wrapper
9 return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13 print(f"User {user_id} has been deleted.")
14
15delete_user(123) # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456) # Permission denied!
Декоратор requires_permission
ограничивает выполнение функции в зависимости от роли пользователя. Собрав такую логику в декоратор, вы можете избежать её рассеивания по всему коду, что повысит читаемость.
Вложенные декораторы
Можно применить несколько декораторов. Когда к одной функции применяются несколько декораторов, они выполняются в порядке сверху вниз.
1def uppercase(func):
2 def wrapper(*args, **kwargs):
3 result = func(*args, **kwargs)
4 return result.upper()
5 return wrapper
6
7def exclaim(func):
8 def wrapper(*args, **kwargs):
9 result = func(*args, **kwargs)
10 return result + "!"
11 return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16 return f"Hello, {name}"
17
18print(greet("Alice")) # "HELLO, ALICE!"
В этом примере к функции greet
применяются два декоратора. Декоратор @exclaim
добавляет восклицательный знак в конец строки, а @uppercase
преобразует строку в верхний регистр.
Декораторы для методов классов
Декораторы также могут использоваться с методами классов. Это особенно полезно, когда вы хотите контролировать поведение методов внутри класса. При применении декораторов к методам класса необходимо учитывать такие аргументы, как self
или cls
.
1def log_method_call(func):
2 def wrapper(self, *args, **kwargs):
3 print(f"Calling method '{func.__name__}'...")
4 return func(self, *args, **kwargs)
5 return wrapper
6
7class MyClass:
8 @log_method_call
9 def greet(self, name):
10 print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")
В этом примере декоратор log_method_call
применяется к методу greet
для вывода лога при его вызове.
Предостережения при использовании декораторов
Есть некоторые аспекты, которые нужно учитывать при использовании декораторов. Декораторы могут изменить имя и строку документации исходной функции (например, __name__
или __doc__
), поэтому рекомендуется использовать functools.wraps
для сохранения этой информации.
1import functools
2
3def my_decorator(func):
4 @functools.wraps(func)
5 def wrapper(*args, **kwargs):
6 print("Before the function call")
7 return func(*args, **kwargs)
8 return wrapper
Использование @functools.wraps
гарантирует правильную передачу метаданных исходной функции в обёрточную функцию.
Резюме
Декораторы Python — это очень мощный инструмент, который позволяет лаконично добавлять дополнительную функциональность в функции и методы. Их можно использовать в различных сценариях, чтобы уменьшить дублирование кода и улучшить его поддерживаемость и повторное использование. Понимая, как работают декораторы, вы сможете писать более эффективный и гибкий код.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.