Представьте себе, если бы вы могли применить декоратор к присваиванию обычной переменной, например:
def add1(x):
return x + 1
@add1
number = 5
Аналогичное поведение для декоратора функции было бы следующим:
number = 5
number = add1(number)
This приведет к присвоению значения 6
переменной number
. Теперь представьте, что декоратор был просто вызван, ничего не возвращая:
number = 5
add1(number)
Нет способа, которым этот код мог бы присвоить 6
переменной number
, потому что number
это , переданный значение не по ссылке ; в Python функция не может присвоить новое значение переменной в совершенно другой области, к которой она не имеет доступа.
Оператор def
действительно является своего рода присваиванием; он присваивает функции имя, с которым вы ее определили. Например, определение функции def func(): pass
компилируется в байт-код, который выполняет STORE_NAME
, то есть присваивание:
1 0 LOAD_CONST 0 (<code object func at ...>)
3 LOAD_CONST 1 ('func')
6 MAKE_FUNCTION 0
9 STORE_NAME 0 (func)
Таким образом, поведение декораторов функций работает так же, как и выше, по той же причине; функция декоратора не может переназначить новую функцию переменной func
в совершенно другой области видимости, потому что func
передается декоратору по значению, а не по ссылке.
Эквивалентность func = decorator(func)
фактически является немного вводит в заблуждение. Чтобы быть полностью правильным, когда вы используете декоратор, функция, которую вы определили в операторе def
, передается непосредственно декоратору, а не присваивается локальному имени func
перед передачей. Вот байт-код:
1 0 LOAD_NAME 0 (decorate)
3 LOAD_CONST 0 (<code object func at ...>)
6 LOAD_CONST 1 ('func')
9 MAKE_FUNCTION 0
12 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
15 STORE_NAME 1 (func)
Пошагово:
- Функция
decorate
загружена в стек, - Объект кода для
func
загружается в стек, затем строка 'func'
, затем инструкция MAKE_FUNCTION
превращает эти два в функцию, оставленную в стеке. - Инструкция
CALL_FUNCTION
вызывает decorate
функция (которая все еще находится в стеке) с одним аргументом, функция func
. - Независимо от того, что возвращает функция
decorate
, она остается в стеке и присваивается имени func
с помощью STORE_NAME
инструкция.
Так что, если функция decorator
ничего не возвращает, присваивать имя func
будет нечего - даже оригинальная функция, как в операторе def
.