Python学习——02-Python基础——【6-函数闭包与装饰器】

1.装饰器

1. 什么是装饰器

器即函数

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

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

2.装饰器需要遵循的原则

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

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

3.实现装饰器知识储备

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

4.高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

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

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

1.高阶函数示范

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

输出:

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

2.把函数当做参数传给高阶函数

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

输出:

from the foo
函数<function foo at 0x000001DEFDDC1F28> 运行时间是0.0

3.函数返回值是函数名

 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增加任何新功能

输出:

#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

高阶函数总结
1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

5.函数嵌套

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('林海峰')

输出:

from the foo

6.闭包

闭包:闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

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

输出:

我爸爸是 [caofu]
我爷爷是 [caofu]

 

 

2.无参装饰器

1.无参装饰器

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

基本框架

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 def cal(array):
2     res=0
3     for i in array:
4         res+=i
5     return res
6 
7 cal=timer(cal)
8 cal(range(10))

语法糖@

1 @timer  #@timer就等同于cal=timer(cal)
2 def cal(array):
3     res=0
4     for i in array:
5         res+=i
6     return res
7 
8 cal(range(10))

2.装饰器应用示例

 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 
10 def auth_deco(func):
11     def wrapper(*args,**kwargs):
12         if current_user['username'] and current_user['login']:
13             res=func(*args,**kwargs)
14             return res
15         username=input('用户名: ').strip()
16         passwd=input('密码: ').strip()
17 
18         for index,user_dic in enumerate(user_list):
19             if username == user_dic['name'] and passwd == user_dic['passwd']:
20                 current_user['username']=username
21 
22                 current_user['login']=True
23                 res=func(*args,**kwargs)
24                 return res
25                 break
26         else:
27             print('用户名或者密码错误,重新登录')
28 
29     return wrapper
30 
31 @auth_deco
32 def index():
33     print('欢迎来到主页面')
34 
35 @auth_deco
36 def home():
37     print('这里是你家')
38 
39 def shopping_car():
40     print('查看购物车啊亲')
41 
42 def order():
43     print('查看订单啊亲')
44 
45 print(user_list)
46 # index()
47 print(user_list)
48 home()

输出:

[{'name': 'alex', 'passwd': '123'}, {'name': 'linhaifeng', 'passwd': '123'}, {'name': 'wupeiqi', 'passwd': '123'}, {'name': 'yuanhao', 'passwd': '123'}]
[{'name': 'alex', 'passwd': '123'}, {'name': 'linhaifeng', 'passwd': '123'}, {'name': 'wupeiqi', 'passwd': '123'}, {'name': 'yuanhao', 'passwd': '123'}]
用户名: 

2.带参装饰器

 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()

输出:

巴拉巴拉小魔仙
欢迎来到主页面
巴拉巴拉小魔仙
这里是你家

3.超时装饰器

最近工作有点多,趁周末有空,继续分享我在学习和使用python过程中的一些小tips。

有没有遇到过这样的事情:对数据库执行插入或更新操作,因为数据量大或其他原因,导致此次操作非常耗时,有时甚至等上好几个小时,也无法完成。很郁闷,怎么操作不超时啊?因为数据库配置时超时时间很长,并且有些操作又是需要很长时间的,所以不能修改默认的超时时间。

因为客观条件不允许,我们不能靠数据库超时来终止此次操作,所以必须要在自己的方法逻辑模块里实现超时检测的功能。

在python里有没有可以不用修改原来的方法内部逻辑,就能实现超时检测呢?肯定有啦,就是利用装饰器。装饰器是什么?在博客园找到了一篇介绍文章:函数和方法装饰漫谈(Function decorator)

废话听完,我现在介绍主角出场:超时装饰器,timeout decorator。

超时检测逻辑:启动新子线程执行指定的方法,主线程等待子线程的运行结果,若在指定时间内子线程还未执行完毕,则判断为超时,抛出超时异常,并杀掉子线程;否则未超时,返回子线程所执行的方法的返回值。

在实现过程中,发现python默认模块里是没有方法可以杀掉线程的,怎么办呢?当然先问问google或百度,果然,keill thread这个关键词很热门,很快就搜索到我想要的东西了:"Kill a thread in Python",就是以下这个KThread类,它继承了threading.Thread,并添加了kill方法,让我们能杀掉它:

  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')
原文地址:https://www.cnblogs.com/caofu/p/8757627.html