Python成长之路【第七篇】:Python基础之装饰器

一、什么是装饰器

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

器:器既函数

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

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

1、不能修改装饰器的源代码(开放封闭原则)

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

三、实现装饰器的知识储备

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

四、高阶函数 

高阶函数的定义:

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

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

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

 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 #高阶函数应用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),改变了函数的调用方式
把函数名当做参数传给高阶函数
 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、函数的返回值是一个函数名

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

  不足:不能添加新功能

 五、函数嵌套

def foo(name):
    print("from foo %s" %name)
    def ret():
        print("from ret")
        def bar():
            print("from bar")
        bar()
    ret()
    
foo("Albert")

六、闭包

闭包:在一个作用域里放入定义变量,想当于打了一个包

def foo(name):
    def ret():
        print("123%s"%name)
        def bar():
            print("456%s"%name)
        bar()
    ret()

foo("Albert")

七、没有参数的装饰器

没有参数的装饰器 = 高阶函数 + 函数嵌套

 

基本框架

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

 

加上参数

def timer(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
    return wrapper

 

加上功能

import time

def timer(func):
    def wrapper(*args, **kwargs):
        s_time = time.time()
        func(*args, **kwargs)
        e_time = time.time()
        print("函数【%s】,运行的时间是%s"%(func, e_time - s_time))
    return wrapper

  

加上返回值

import time

def timer(func):
    def wrapper(*args, **kwargs):
        s_time = time.time()
        res = func(*args, **kwargs)
        e_time = time.time()
        print("函数【%s】,运行的时间是%s"%(func, e_time - s_time))
        return res
    return wrapper

  

使用装饰器

def cal(array):
    res = 0
    for i in array:
        res += i
    return res

cal = timer(cal)
a = cal(range(10))
print(a)

 

语法糖@

@timer # @timer == cal = timer(cal)
def cal(array):
    res = 0
    for i in array:
        res += i
    return res


a = cal(range(10))
print(a)

八、装饰器应用示例

 1 user_list=[
 2     {'name':'Albert','passwd':'123'},
 3     {'name':'Seven','passwd':'123'},
 4     {'name':'Eric','passwd':'123'},
 5     {'name':'Mary','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                 current_user['login']=True
22                 res=func(*args,**kwargs)
23                 return res
24         else:
25             print('用户名或者密码错误,重新登录')
26 
27     return wrapper
28 
29 @auth_deco
30 def index():
31     print('欢迎来到主页面')
32 
33 @auth_deco
34 def home():
35     print('这里是你家')
36 
37 def shopping_car():
38     print('查看购物车啊亲')
39 
40 def order():
41     print('查看订单啊亲')
42 
43 
44 index()
45 # home()
无参装饰器
 1 user_list=[
 2     {'name':'Albert','passwd':'123'},
 3     {'name':'Seven','passwd':'123'},
 4     {'name':'Eric','passwd':'123'},
 5     {'name':'Mary','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                 else:
26                     print('用户名或者密码错误,重新登录')
27             elif auth_type == 'ldap':
28                 print('巴拉巴拉小魔仙')
29                 res=func(*args,**kwargs)
30                 return res
31         return wrapper
32     return auth_deco
33 
34 
35 #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file')
36 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
37 @auth(auth_type='file')
38 def index():
39     print('欢迎来到主页面')
40 
41 @auth(auth_type='ldap')
42 def home():
43     print('这里是你家')
44 
45 def shopping_car():
46     print('查看购物车啊亲')
47 
48 def order():
49     print('查看订单啊亲')
50 
51 index()
52 # home()
带参装饰器

 九、超时装饰器

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

 

posted @ 2018-04-09 16:01  Mr_Albert  阅读(145)  评论(0编辑  收藏  举报