1 def square_add(func): 2 def new_function1(*args, **kwargs): 3 result = func(*args, **kwargs) 4 return result ** 2 5 return new_function1 6 7 def document_it(func): 8 def new_function2(*args, **kwargs): 9 print('Running function: ', func.__name__) 10 print('Positional arguments: ', args) 11 print('Keyword arguments: ', kwargs) 12 result = func(*args, **kwargs) 13 print('Result: ', result) 14 return result 15 return new_function2 16 17 #一个函数可以拥有多个装饰器,且从距离该函数def最近的装饰器开始,依次向上执行 18 19 @square_add 20 @document_it 21 def add_ints(a, b): 22 return a + b
add_ints函数本身是计算给定的两个int类型参数的和,但是,在此函数定义之前有“@装饰器名字”的表达式,意味着,该函数被其他函数装饰。所以,add_ints函数的调用结果就不只是求和了。一个函数可以拥有多个装饰器,且从距离该函数def最近的装饰器开始,依次向上执行。装饰器document_it距离被装饰的函数add_ints最近,因此,优先执行该装饰器。当add_ints函数被调用时,即本例中“add_ints(3,5)”,实际执行的过程如下:
1.调用函数document_it(add_ints),我们发现document_it本身是返回了new_function2,调用端用一个名叫add_ints的函数来接收这个new_function2的返回值;
注意:add_ints已经不是那个只求和的函数了
2.add_ints函数实际上现在指向的是new_function2,因为new_function2这个函数(是document_it的内部函数)可以有任意多个位置参数或关键字参数,所以,我们可以通过“add_ints(3,5)”这样的方式,来给new_function2传入一组位置参数(以元组的形式将3、5传入);
3.执行new_function2的函数体,很明显,print('Running function: ', func.__name__),这条语句中func是指add_ints;args位置参数是一个元祖(3,5);kwargs关键字参数没有传入参数,所以是空字典;接下来是这条语句“result = func(*args, **kwargs)”,我们已经知道func实际是指add_ints,那么func(*args, **kwargs)就相当于add_ints(3,5),因此,result的值就是add_ints(3,5)的返回值,即8;紧接着print打印result的值:8;最后返回result的值8;到这一步,document_it这个装饰器已经执行完毕,接下来就是执行下一个装饰器square_add。
4.执行square_add(func),此时,func是指?由上面的分析,我们可知,被document_it装饰后的add_ints函数,实际上是指new_function2,所以,在执行square_add(func)时,func就是指的new_function2。为了证明这一点,我们可以在square_add这个函数中加一句print(func):
5.由第4步可知,程序实际上是执行square_add(new_function2),而square_add函数是返回new_function1函数,同样用名字叫做add_ints的变量来接收这个函数,也就是说,此时add_ints实际上是指向new_function1:
6.执行add_ints(3,5)就相当于new_function1(3,5),即执行的是new_function1的函数体,此时new_function1的参数是位置参数元组(3,5)。由于此时的func是指new_function2,所以,result = func(*args, **kwargs)就相当于将new_function2(3,5)的返回值赋值给result,我们已经明白new_function2(3,5)恰好是装饰器document_it的返回值8,因此,result = 8;接下来,返回8的平方,即64.
综上所述,最终的执行结果是:
>>> add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
64
>>>