Python--装饰器

一、什么是装饰器

  解释:

    器即函数

    装饰即修饰,意指为其他函数添加新功能

    装饰器的定义:本质上就是函数,功能是为其他函数添加新的功能

二、装饰器需要遵循的原则

  原则:

    1、不修改被装饰函数的源代码(开放封闭原则)

    2、为被装饰函数添加新功能后,不修改被修饰函数的调用方式

三、实现装饰器知识储备

  装饰器=高阶函数+函数嵌套+闭包

四、高阶函数

  高阶函数的定义:

    1、函数接收的参数是一个函数名

    2、函数的返回值是一个函数名

    3、满足上述条件任意一个,都可称之为高阶函数

 1 def foo():
 2     print('我的函数名作为参数传给高阶函数')
 3 
 4 def gaojie1(func):
 5     print('我就是高阶函数1,我接收的参数名为%s'%func)
 6     func()
 7 
 8 def gaojie2(func):
 9     print('我就是高阶函数2,我的返回值是%s'%func)
10     return func
11 
12 gaojie1(foo)
13 gaojie2(foo)

输出结果:

1 我就是高阶函数1,我接收的参数名为<function foo at 0x0000000002081EA0>
2 我的函数名作为参数传给高阶函数
3 我就是高阶函数2,我的返回值是<function foo at 0x0000000002081EA0>

应用一:把函数作为参数传递给高阶函数

 1 # 高阶函数的应用1:把函数作为参数传给高阶函数
 2 import time
 3 def foo():
 4     print('from the foo')
 5 
 6 def timmer(func):
 7     start_time=time.time()
 8     time.sleep(1)
 9     func()
10     stop_time=time.time()
11     print('函数%s,运行时间是%s'%(func,stop_time-start_time))
12 
13 timmer(foo)
14 #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的
15 #执行方式是foo(),现在我们需要高阶函数timmer(foo),改变了函数的
16 #调用方式

  应用二:把函数名当做参数传递给高阶函数,高阶函数直接返回函数名

 1 #高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
 2 import time
 3 def foo():
 4     print('from the foo')
 5 
 6 def timmer(func):
 7     start_time=time.time()
 8     return func
 9     stop_time=time.time()
10     print('函数%s运行时间是%s'%(func,stop_time-start_time))
11 foo=timmer(foo)
12 foo()
13 #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何功能

高阶函数总结:

  1、函数接收的参数是一个函数名

    作用:在不修改函数源代码的前提下,为函数添加新功能

    不足:会改变函数的调用方式

  2、函数的返回值是一个函数名

    作用:不修改函数的调用方式

    不足:不能添加新的功能

五、函数嵌套

  描述:在函数内部定义函数

  代码:

 1 def father(name):
 2     print('from father %s'%name)
 3     def son():
 4         print('from son')
 5         def grandson():
 6             print('from grandson')
 7         grandson()
 8     son()
 9 
10 father('baba')

 

六、闭包

  

 1 # 闭包:在一个作用域里放入定义变量,相当于打了一个包
 2 def father(name):
 3     def son():
 4         #name='alex'
 5         print('我爸爸是[%s]' %name)
 6         def grandson():
 7             #name='alex'
 8             print('我的爷爷是[%s]'%name)
 9         grandson()
10     son()
11 father('alex')

 

七、无参装饰器

  无参修饰器=高级函数+函数嵌套

  基本框架:

1 #这就是一个实现一个装饰器最基本的架子
2 def timer(func):
3     def wrapper():
4         func()
5     return wrapper

  加上参数:

1 def timer(func):
2     def wrapper(*args,**kwargs):
3         func(*args,**kwargs)
4     return wrapper

  加上功能:

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数%s,运行时间是%s',%(func,stop_time-start_time))
8         return wrapper

  加上返回值:

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         res=func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数%s,运行时间%s'%(func,stop_time-start_time))
8         return res
9     return wrapper

 

  使用修饰器:

 1 import time
 2 def timer(func):
 3     def wrapper(*args,**kwargs):
 4         start_time=time.time()
 5         res=func(*args,**kwargs)
 6         stop_time=time.time()
 7         print('函数%s,运行时间%s'%(func,stop_time-start_time))
 8         return res
 9     return wrapper
10 
11 def cal(array):
12     res=0
13     for i in array:
14         res+=i
15     return res
16 cal=timer(cal)
17 print(cal(range(10)))

  语法糖@:

 1 import time
 2 def timer(func):
 3     def wrapper(*args,**kwargs):
 4         start_time=time.time()
 5         res=func(*args,**kwargs)
 6         stop_time=time.time()
 7         print('函数%s,运行时间%s'%(func,stop_time-start_time))
 8         return res
 9     return wrapper
10 @timer
11 def cal(array):
12     res=0
13     for i in array:
14         res+=i
15     return res
16 #cal=timer(cal)
17 print(cal(range(10)))

 

八、装饰器应用示例

 1 user_list=[
 2     {'name':'alex','passwd':'123'},
 3     {'name':'wangjun','passwd':'123'},
 4     {'name':'liuchao','passwd':'123'},
 5     {'name':'qiaobusi','passwd':'123'}
 6 ]
 7 current_user={'username':None,'login':False}
 8 
 9 def auth_deco(func):
10     def wrapper(*args,**kwargs):
11         if current_user['username'] and current_user['login']:
12             res=func(*args,**kwargs)
13             return res
14         username=input('用户名:').strip()
15         passwd=input('密码:').strip()
16         for index,user_dic in enumerate(user_list):
17             if username==user_dic['name'] and passwd==user_dic['passwd']:
18                 current_user['username']=username
19                 current_user['login']=True
20                 res=func(*args,**kwargs)
21                 return res
22                 break
23             else:
24                 print('用户名或者密码错误')
25     return wrapper
26 
27 @auth_deco
28 def index():
29     print('欢迎来到主页面')
30 
31 @auth_deco
32 def home():
33     print('这里是你家')
34 
35 def shopping_car():
36     print('查看购物车啊亲')
37 
38 def order():
39     print('查看订单啊亲')
40 
41 index()
42 home()
 1 user_list=[
 2     {'name':'alex','passwd':'123'},
 3     {'name':'linhaifeng','passwd':'123'},
 4     {'name':'wupeiqi','passwd':'123'},
 5     {'name':'yuanhao','passwd':'123'},
 6 ]
 7 
 8 current_user={'username':None,'login':False}
 9 def auth(auth_type='file'):
10     def auth_deco(func):
11         def wrapper(*args,**kwargs):
12             if auth_type == 'file':
13                 if current_user['username'] and current_user['login']:
14                     res=func(*args,**kwargs)
15                     return res
16                 username=input('用户名: ').strip()
17                 passwd=input('密码: ').strip()
18 
19                 for index,user_dic in enumerate(user_list):
20                     if username == user_dic['name'] and passwd == user_dic['passwd']:
21                         current_user['username']=username
22                         current_user['login']=True
23                         res=func(*args,**kwargs)
24                         return res
25                         break
26                 else:
27                     print('用户名或者密码错误,重新登录')
28             elif auth_type == 'ldap':
29                 print('巴拉巴拉小魔仙')
30                 res=func(*args,**kwargs)
31                 return res
32         return wrapper
33     return auth_deco
34 
35 
36 #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file')
37 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
38 @auth(auth_type='ldap')
39 def index():
40     print('欢迎来到主页面')
41 
42 @auth(auth_type='ldap')
43 def home():
44     print('这里是你家')
45 
46 def shopping_car():
47     print('查看购物车啊亲')
48 
49 def order():
50     print('查看订单啊亲')
51 
52 # print(user_list)
53 index()
54 # print(user_list)
55 home()
56 
57 带参装饰器

 

九、超时装饰器

  1 import sys,threading,time
  2 
  3 
  4 class KThread(threading.Thread):
  5 
  6     """A subclass of threading.Thread, with a kill()
  7 
  8     method.
  9 
 10 
 11 
 12     Come from:
 13 
 14     Kill a thread in Python:
 15 
 16     http://mail.python.org/pipermail/python-list/2004-May/260937.html
 17 
 18     """
 19 
 20     def __init__(self, *args, **kwargs):
 21 
 22         threading.Thread.__init__(self, *args, **kwargs)
 23 
 24         self.killed = False
 25 
 26 
 27 
 28     def start(self):
 29 
 30         """Start the thread."""
 31 
 32         self.__run_backup = self.run
 33 
 34         self.run = self.__run      # Force the Thread to install our trace.
 35 
 36         threading.Thread.start(self)
 37 
 38 
 39 
 40     def __run(self):
 41 
 42         """Hacked run function, which installs the
 43 
 44         trace."""
 45 
 46         sys.settrace(self.globaltrace)
 47 
 48         self.__run_backup()
 49 
 50         self.run = self.__run_backup
 51 
 52 
 53 
 54     def globaltrace(self, frame, why, arg):
 55 
 56         if why == 'call':
 57 
 58           return self.localtrace
 59 
 60         else:
 61 
 62           return None
 63 
 64 
 65 
 66     def localtrace(self, frame, why, arg):
 67 
 68         if self.killed:
 69 
 70           if why == 'line':
 71 
 72             raise SystemExit()
 73 
 74         return self.localtrace
 75 
 76 
 77 
 78     def kill(self):
 79 
 80         self.killed = True
 81 
 82 
 83 
 84 class Timeout(Exception):
 85 
 86     """function run timeout"""
 87 
 88 
 89 
 90 def timeout(seconds):
 91 
 92     """超时装饰器,指定超时时间
 93 
 94     若被装饰的方法在指定的时间内未返回,则抛出Timeout异常"""
 95 
 96     def timeout_decorator(func):
 97 
 98         """真正的装饰器"""
 99 
100 
101 
102         def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
103 
104             result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
105 
106 
107 
108         def _(*args, **kwargs):
109 
110             result = []
111 
112             new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list
113 
114                 'oldfunc': func,
115 
116                 'result': result,
117 
118                 'oldfunc_args': args,
119 
120                 'oldfunc_kwargs': kwargs
121 
122             }
123 
124             thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
125 
126             thd.start()
127 
128             thd.join(seconds)
129 
130             alive = thd.isAlive()
131 
132             thd.kill() # kill the child thread
133 
134             if alive:
135 
136                 raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
137 
138             else:
139 
140                 return result[0]
141 
142         _.__name__ = func.__name__
143 
144         _.__doc__ = func.__doc__
145 
146         return _
147 
148     return timeout_decorator
149 
150 
151 @timeout(5)
152 
153 def method_timeout(seconds, text):
154 
155     print('start', seconds, text)
156 
157     time.sleep(seconds)
158 
159     print('finish', seconds, text)
160 
161     return seconds
162 
163 
164 method_timeout(6,'asdfasdfasdfas')

 

posted @ 2019-05-10 16:43  王者or青铜  阅读(171)  评论(1编辑  收藏  举报