В Python, в чем разница между использованием одного и того же декоратора с круглыми скобками и без них?
Например:
Без скобок:
@some_decorator
def some_method():
pass
С круглыми скобками:
@some_decorator()
def some_method():
pass
В Python, в чем разница между использованием одного и того же декоратора с круглыми скобками и без них?
Например:
Без скобок:
@some_decorator
def some_method():
pass
С круглыми скобками:
@some_decorator()
def some_method():
pass
some_decorator
в первом фрагменте кода является обычным декоратором:
@some_decorator
def some_method():
pass
эквивалентно
some_method = some_decorator(some_method)
С другой стороны, some_decorator
во втором фрагменте кода является вызываемым, который возвращает декоратор:
@some_decorator()
def some_method():
pass
эквивалентно
some_method = some_decorator()(some_method)
Как отметил Дункан в комментариях, некоторые декораторы предназначены для работы в обоих направлениях. Вот довольно базовая реализация такого декоратора:
def some_decorator(arg=None):
def decorator(func):
def wrapper(*a, **ka):
return func(*a, **ka)
return wrapper
if callable(arg):
return decorator(arg) # return 'wrapper'
else:
return decorator # ... or 'decorator'
pytest.fixture
является более сложным примером.
Некоторый реально работающий код, где вы используете arg внутри декоратора:
def someDecorator(arg=None):
def decorator(func):
def wrapper(*a, **ka):
if not callable(arg):
print (arg)
return func(*a, **ka)
else:
return 'xxxxx'
return wrapper
if callable(arg):
return decorator(arg) # return 'wrapper'
else:
return decorator # ... or 'decorator'
@someDecorator(arg=1)
def my_func():
print('aaa')
@someDecorator
def my_func1():
print('bbb')
if __name__ == "__main__":
my_func()
my_func1()
Выход:
1
aaa
Вкратце, декораторы позволяют добавлять богатые функции к группам функций и классов, не изменяя их вообще.
Ключом к пониманию разницы между @some_decorator
и @some_decorator()
является то, что первый является декоратором, а второй - функцией (или вызываемой), которая возвращает декоратор.
Я считаю, что наблюдение за реализацией каждого случая помогает понять разницу:
@some_decorator
def some_decorator(func):
def wrapper(func):
return func(*args, **kwargs)
return wrapper
Заявка:
@some_decorator
def some_method():
pass
Эквивалент:
some_method = some_decorator(some_method)
@some_decorator()
def some_decorator():
def decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
Заявка:
@some_decorator()
def some_method():
pass
Эквивалент:
some_method = some_decorator()(some_method)
Обратите внимание, что теперь легче видеть, что @some_decorator()
- это функция, возвращающая декоратор, а some_decorator
- просто декоратор. Имейте в виду, что некоторые декораторы написаны так, чтобы работать в обоих направлениях.
Так что теперь вам может быть интересно, почему у нас есть эти два случая, когда предыдущая версия кажется проще. Ответ в том, что если вы хотите передать аргументы декоратору, использование @some_decorator()
позволит вам сделать это. Давайте посмотрим код в действии:
def some_decorator(arg1, arg2):
def decorator(func):
def wrapper(*args, **kwargs):
print(arg1)
print(arg2)
return func(*args, **kwargs)
return wrapper
return decorator
Заявка:
@some_decorator('hello', 'bye')
def some_method():
pass
Эквивалент:
some_method = some_decorator('hello', 'bye')(some_method)
Примечание: я думаю, что стоит упомянуть, что декоратор может быть реализован как функция или как класс. Проверьте это для получения дополнительной информации.