python装饰器的参数传递
被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行)(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,会调用到装饰器内部的那个函数()
装饰器:在不修改函数源代码的基础上,添加函数功能
def log_time(func): # 此函数的作用时接受被修饰的函数的引用test,然后被内部函数使用 def make_decorater(): print('现在开始装饰') func() print('现在结束装饰') return make_decorater # log_time()被调用后,运行此函数返回make_decorater()函数的引用make_decorater @log_time # 此行代码等同于,test=log_time(test)=make_decorater def test(): print('我是被装饰的函数') test() # test()=make_decorater()
D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
现在开始装饰
我是被装饰的函数
现在结束装饰
当被装饰的函数有形参时
def log_time(func): def make_decorater(*args,**kwargs): # 接受调用语句的实参,在下面传递给被装饰函数(原函数) print('现在开始装饰') test_func = func(*args,**kwargs) # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回 print('现在结束装饰') return test_func # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。 return make_decorater @log_time def test(num): print('我是被装饰的函数') return num+1 a = test(2) # test(2)=make_decorater(2) print(a)
D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
现在开始装饰
我是被装饰的函数
现在结束装饰
两个装饰器同时修饰一个函数(重点看执行顺序)
如何理解顺序
@log_time1是修饰@log_time2和test两个函数
@log_time2只是修饰test一个函数
def log_time1(func): def make_decorater(*args,**kwargs): print('1现在开始装饰') test_func = func(*args,**kwargs) print('1现在结束装饰') return test_func return make_decorater def log_time2(func): def make_decorater(*args,**kwargs): # 接受调用语句的实参,在下面传递给被装饰函数(原函数) print('2现在开始装饰') test_func = func(*args,**kwargs) # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回 print('2现在结束装饰') return test_func # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。 return make_decorater @log_time1 @log_time2 def test(num): print('我是被装饰的函数') return num+1 a = test(2) # test(2)=make_decorater(2) print(a)
D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
1现在开始装饰
2现在开始装饰
我是被装饰的函数
2现在结束装饰
1现在结束装饰
3
如果语法糖带有参数:
import time def foo(*args, **kwargs): def loo(func): print('from the loo', *args, **kwargs) def xoo(*args, **kwargs): print('from the xoo', *args, **kwargs) start_time = time.time() func(*args, **kwargs) stop_time = time.time() print('test time=%s' % (stop_time - start_time)) print(*args, **kwargs) return xoo return loo @foo('hello from decoration') def test(*args, **kwargs): time.sleep(1) print('test is over') test('nihao', 'from the test')
from the loo hello from decoration from the xoo nihao from the test test is over test time=1.0000572204589844 nihao from the test
语法糖带有参数的目的是在原有装饰器的基础上,再加上一个参数, 根据参数在对内部函数进行装饰处理,所以有人给出2个装饰器装饰一个函数,就没有太大的必要性了, 完全可以在语法糖的基础上给予一个参数 ---可以是函数进行装饰
所以对于2个装饰器的例子,我们可以这样修改一下:
def foo(*args,**kwargs): print(*args,**kwargs) def log_time1(func): def make_decorater(*args, **kwargs): print('1现在开始装饰') test_func = func(*args, **kwargs) print('1现在结束装饰') return test_func return make_decorater return log_time1 @foo('1来自语法糖的参数') def test(num): print('我是被装饰的函数') return num + 1 a = test(2) # test(2)=make_decorater(2) print(a)
1来自语法糖的参数
1现在开始装饰
我是被装饰的函数
1现在结束装饰
如何语法糖传入的参数是函数呢?
我把上面2个语法糖的例子做了修改,看结果
def foo(x): def log_time1(func): def make_decorater(*args, **kwargs): x() print('1现在开始装饰') test_func = func(*args, **kwargs) print('1现在结束装饰') return test_func return make_decorater return log_time1 def goo(): print('from the goo' ) # @log_time1 # @log_time2 @foo(goo) def test(num): print('我是被装饰的函数') return num + 1 # # a = test(2) # test(2)=make_decorater(2) # print(a)
from the goo 1现在开始装饰 我是被装饰的函数 1现在结束装饰
语法糖的参数传递功能扩展了装饰器的功能。