python:关于嵌套装饰器

装饰器

  • 1. 关于函数属性
  • 2.嵌套装饰器的练习

1. 关于函数属性

code:

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 30 19:51:10 2019

@author: buu
"""
'''
通过下面的代码可以看出:
1. 有@functool.wraps()时,函数testfunc1()是它自己,即;
2. 没有@functools.wraps(),函数testfunc1()指向了wrapper_func(),即.wrapper_func at 0x00000000086A0488>;
3. 对于闭包函数的属性的查看: 
   不管有没有@functool.wraps(),函数testfun()仍拥有wrapper_func.time这个属性,并且testfunc1可以修改,
   但对这个属性的修改仅限于testfunc1()本身,并不改变wrapper_func.time的值;

'''

import functools
def wrap(func):
    @functools.wraps(func)
    def wrapper_func():
        print('inside:')
        wrapper_func.time+=3
        func()
    wrapper_func.time=1
    return wrapper_func
@wrap
def testfunc1():
    print('test 1')
@wrap
def testfunc2():
    print('test 2')
if __name__ == '__main__':
    testfunc1()
#    print('without functools:',testfun)
    #without functools: .wrapper_greet at 0x00000000070D9598>
    print('with functools:',testfunc1)
    #have functools: 
    #    print(wrapper_greet.time) 
    # 尝试直接输出wrapper_greet.time: NameError: name 'wrapper_greet' is not defined
    print('-'*40)
    print('首先查看testfunc1是否包含time属性:',dir(testfunc1)) # 包含
    print('-'*40)
    print('初始时wrapper_func.time:',wrap(testfunc2).time)
    # wrap()总得需要一个参数,此处若用testfunc1的话,输出的还是testfunc1的time属性;
    print('testfunc1.time=',testfunc1.time)# 
    testfunc1.time=2
    print('testfun1对time进行修改,修改testfunc1.time=',testfunc1.time) # 
    print('看看wrapper_greet.time是否被修改:',wrap(testfunc2).time) # 
    print()
    testfunc2()
    testfunc2.age=10
    print('testfun2未被装饰时包含的属性:包含age')
    print('testfun2被装饰后包含的属性:包含age和time')

结果:
python:关于嵌套装饰器_第1张图片

2.嵌套装饰器的练习

practice:

  1. bubble_sort.py
    Python代码a, b = b, a称为一次swap .
    函数bubble_sort(L, func=operator.lt), 功能为对整数list L进行in-place 冒泡排序, 返回 swap count, 比较规则为func, func缺省为小于(operator.lt, 即<) 最后返回交换次数;

  2. dec_func.py
    写一个 function decorator 来装饰 bubble_sort() 函数, 该函数请从bubble_sort.py 中直接 import, 装饰器的功能是报告每一次bubble sort完成排序工作所花去的时间(以秒计), 并最终统计调用次数和总时间花销(即累加各次的时间花销).
    一次输出为:
    在这里插入图片描述

  3. dec_nested.py
    写两个 decorators 来嵌套装饰 bubble_sort() 函数, 第一个装饰器函数 timer() 从第40题的dec_func.py中直接import.
    一次输出为:
    python:关于嵌套装饰器_第2张图片
    code1: bubble_sort.py

def bubble_sort(L,func=operator.lt): # func:<
    '''
    将L从小到大排序;
    '''
    swap_count=0
    length=len(L)
    l=len(L)
    for i in range(length): # 用来控制一趟冒泡排序;
        for j in range(l-1):# j取值:0-->length-2 ,用来控制每趟排序的交换次数;
            if not func(L[j],L[j+1]):
                L[j],L[j+1]=L[j+1],L[j]
                swap_count+=1
        l-=1 # 一趟结束后,最大的沉底,所以最大的不必再参与排序;
    return swap_count

code2: dec_func.py

# -*- coding: utf-8 -*-
"""
Created on Fri Nov 22 09:13:02 2019

@author: buu
"""
import numpy as np
import operator,functools,time
from bubble_sort import bubble_sort

def timer(func):
    @functools.wraps(func)
    def wrapper_timer(ls,g):
        wrapper_timer.ncalls+=1
        print("排序前序列的前5个数为:",end='')
        for i in range(5):
            print(ls[i],end=' ')
        print()
        t0=time.time()
        swapcnt= func(ls,g)
        t=time.time()-t0
        print("排序后序列的前5个数为:",end='')
        for i in range(5):
            print(ls[i],end=' ')
        print()
        print(f"bubble_sort花了{t:.4f}秒,swapcount = {swapcnt}")
        wrapper_timer.time+=t
        return swapcnt
    wrapper_timer.time=0
    wrapper_timer.ncalls=0
    return wrapper_timer
if __name__ == '__main__':
    bubble_sort = timer(bubble_sort)
    for i in range(np.random.randint(3,8)):
         n=np.random.randint(1000, 3001)
         L=list(np.random.permutation(n))
         func = operator.gt
         swapcnt = bubble_sort(L, func)
    print(f'\n共调用{bubble_sort.__name__}函数{bubble_sort.ncalls}次, 总时间为{bubble_sort.time:.2f}秒.',end='')

code2输出:
python:关于嵌套装饰器_第3张图片
code3:dec_nested.py

# -*- coding: utf-8 -*-
"""
Created on Fri Nov 22 16:12:12 2019

@author: buu
"""
import numpy as np
import operator, functools, time, sys
from bubble_sort import bubble_sort
from dec_func import timer

def star(c1='-', c2='*', repeat=42):
    def wrapper_star(func):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            wrapper.ncalls+=1
            print(f"第{wrapper.ncalls}次调用{func.__name__}:")
            print(c1*repeat)
            t0=time.time()
            ret=func(*args,**kwargs)
            t=time.time()-t0
            wrapper.time+=t
            print(c2*repeat)
            print()
            return ret
        wrapper.ncalls=0
        wrapper.time=0
        return wrapper
    return wrapper_star

if len(sys.argv) == 1:
    bubble_sort = star()(timer(bubble_sort))
else:
	bubble_sort = star(c1=sys.argv[1],c2=sys.argv[2],repeat=int(sys.argv[3]))(timer(bubble_sort))


for i in range(np.random.randint(3, 8)):
    n = np.random.randint(1000, 3001)
    L = list(np.random.permutation(n))
    func = operator.gt
    cnt=bubble_sort(L,func)
print(f'\n共调用{bubble_sort.__name__}函数\
{bubble_sort.ncalls}, 总时间为{bubble_sort.time:.2f}.')

code3输出:部分结果

python:关于嵌套装饰器_第4张图片
下面说一下为什么在code3中,装饰器star()内要再次定义time,ncalls变量:
因为star()有缺省参数,因此需要写成3个函数嵌套;
2个嵌套就能直接获取func.ncalls or func.time,但是3层嵌套就不行了.

end

你可能感兴趣的:(python3)