我们有一个简单的装饰器和一个我们想要添加附加功能的函数:
def wrap(func):
def mod():
up = func()
mod_up = up.upper()
return mod_up
return mod
def up_str():
return 'hello Maksim'
我们可以通过三种方式装饰和调用我们的原始函数:
#1) Просто вызывать функцию wrap c передачей ей в качестве параметра функции uper_str.
print(wrap(up_str)()) #Вывод: HELLO MAKSIM Важным моментом является то, что мы всегда возвращаем в return не результат вызова
#функции(с круглыми скобочками), а сам объект функции(без круглых скобочек).
# Этап вызова нашей функции ^^^ когдa выполняется return mod, объект функции mod перемещается в область видимости wrap, что образно можно представить так:
def wrap(func):
mod
# А затем к возвращённому mod применяется оператор круглых скобочек (), которые мы дописали в конце вызова wrap выше. То есть вызывается функция mod() - происходит то же самое, что и в предыдущий раз тело функции mod как бы перемещается в область видимости wrap:
def wrap(func):
up = func()
mod_up = up.upper() # эти две строчки сразу возвращаются в виде результата вызова mod() - return mod_up. Это просто образное представление происходящих процессов, чтобы в том числе объяснить, как параметр func может передаться в up = func() - благодаря попадaнию в область видимости wrap.
# (Если что я просто образно представляю порядок выполнения кода)
#2) Переопределить функцию up_str. Логика "превращений" та же только добавляется новое звено: wrap(up_str)-->mod-->up_str. Чтобы активировать переопределённую функцию к ней так же надо добавить оператор круглых скобок () :
up_str = wrap(up_str)
print(up_str()) #Вывод: HELLO MAKSIM
# В этом случае после переопределения функции up_str мы теряем её исходный функционал, но мы всегда можем сохранить исходную функцию в другую переменную до её переопределения и таким образом ничего не потерять.
#3) Ну и с помощью синтаксического сахара:
@wrap
def up_str():
return 'hello Maksim'
print(up_str())#Вывод: HELLO MAKSIM
前两种方法中,函数是在函数调用阶段进行修饰的。在后者中,在定义函数的阶段。这导致了以下问题:
- 当用@修饰时,在定义up_str的阶段,顺序会发生什么?
- 如何在使用@时同时保留原始函数和修饰后的函数?