装饰器

一,装饰器的概念

器即函数

装饰即修饰,顾名思义就是为其他函数添加新功能

装饰器的定义:装饰器本质上就是一个函数,这个函数接收其他函数做为参数,并将以一个新的修改后的函数进行替换。装饰器的应用场景就是对

多个函数提供在其之前,之后或周围进行调用的通用代码

 

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

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

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

 

三,上面刚刚有写到装饰器本身就是函数,只是这个函数的功能比普通函数的功能要强大很多,那么一个函数怎样才能是一个装饰器呢

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

以前在博客中有写过什么是高阶函数,函数嵌套,现在我们在来回顾一下

3.1高阶函数的定义

3.1.1函数接收的参数是一个函数名

3.1.2函数的返回值是一个函数名

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

 1 def foo():
 2     print('我的函数名做为高阶函数的参数,传给高阶函数')
 3 
 4 def test_one(func):
 5     print('我是高阶函数1,我接收的参数是%s'%func)
 6     func()
 7 
 8 def test_two(func):
 9     print('我是高阶函数2,我的返回值是%s' %func)
10     return func
11 
12 test_one(foo)
13 ######执行结果#########
14 #我是高阶函数1,我接收的参数是<function foo at 0x0000000001140048>
15 #我的函数名做为高阶函数的参数,传给高阶函数
16 
17 test_two(foo)
18 ######执行结果#########
19 #我是高阶函数2,我的返回值是<function foo at 0x00000000006F0048>

 

 1 #高阶函数应用1:把函数名当做参数传给高阶函数
 2 #我们来计算一下foo这个函数执行花了多长时间
 3 
 4 import time
 5 def foo():
 6     time.sleep(1)
 7     print('我是函数foo,我的运行时间是多久')
 8 
 9 def test(func):
10     '''
11     计算foo这个函数运行时间
12     :param func: 将foo这个函数作为参数,计算运行时间
13     :return:
14 
15     '''
16     start_time = time.time()
17     func()
18     stop_time = time.time()
19     print('函数foo的运行时间是%s' % (stop_time - start_time))
20 
21 test(foo)
22 
23 #########执行结果#######
24 #我是函数foo,我的运行时间是多久
25 #函数foo的运行时间是1.0000572204589844
26 
27 #总结:在这个示例中,我们虽然为foo增加了计算运行时间的功能,但是foo原来的执行
28 方式是foo(),现在我们需要调用高阶函数test(foo),改变了函数的调用方式
 1 #高阶函数应用2:把函数名当作参数传给高阶函数,高阶函数直接返回函数名
 2 
 3 import time
 4 def foo():
 5     time.sleep(1)
 6     print('我是函数foo,我的运行时间是多久')
 7 
 8 def test(func):
 9     '''
10     计算foo这个函数运行时间
11     :param func: 将foo这个函数作为参数,计算运行时间
12     :return:
13 
14     '''
15     start_time = time.time()
16     return func
17     stop_time = time.time()
18     print('函数%s的运行时间是%s' % (func,stop_time - start_time))
19     
20 foo = test(foo)
21 foo()
22 
23 ######执行结果########
24 #我是函数foo,我的运行时间是多久
25 
26 
27 #总结:这次执行我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

高阶函数总结:

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

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

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

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

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

  不足:不能添加新功能

3.2 函数嵌套

 1 user_name = 'jack'
 2 def test_one(name):
 3     print('my name is %s' %name)
 4     def test_two():
 5         name = 'zcy'
 6         print('test-two:%s' %name)
 7         def test_three():
 8             print('test_three',name)
 9         test_three()
10     test_two()
11 test_one(user_name)
12 
13 #########执行结果######
14 #my name is jack
15 #test-two:zcy
16 #test_three zcy

 

3.3闭包

 1 def test_one(name):
 2     '''
 3     闭包:在一个作用域里放入定义变量,相当于打了一个包
 4     :param name:
 5     :return:
 6     '''
 7     print('my name is %s' %name)
 8     def test_two():
 9         name = 'zcy'
10         print('test-two:%s' %name)
11         def test_three():
12             print('test_three',name)
13         test_three()
14     test_two()
15 test_one('laiying')
16 
17 #########执行结果#########
18 #my name is laiying
19 #test-two:zcy
20 #test_three zcy

 

四.无参装饰器

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

接下来我们开始创建装饰器

我们先来创建一个最简单的装饰器,

 1 def test(func):
 2     return func
 3 
 4 @test
 5 def foo(name):
 6     print('My name is %s' %name)
 7 foo('laiying')
 8 
 9 #它和下面的过程类似
10 
11 def test(func):
12     return func
13 
14 def foo(name):
15     print('My name is %s' % name)
16 foo = test(foo)
17 
18 #这个装饰器没什么用,但是可以正常运行,只不过它什么都不做

 

语法糖@

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

 

接下来我们有一个要求,比如视频刚上线初期,为了吸引用户,你们采取了免费政策,所有视频免费观看,迅速吸引了一大批用户,免费一段时间后,每天巨大的带宽费用公司承受不了了,所以准备对比较受欢迎的几个版块收费,其中包括“欧美” 和 “日韩”专区。

接下来要这样才能实现这个要求呢

思路:想收费得先让其进行用户认证,认证通过后,再判定这个用户是否是VIP付费会员就可以了,是VIP就让看,不是VIP就不让看就行了

注意事项:在我们要修改代码前,一定要遵循软件开发原则中的一个“开发-封闭”原则,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

封闭:已实现的功能代码块

开放:对扩展开发

user_dic = [
    {'name':'laiying','pwd':123},
    {'name':'zcy','pwd':123},
    {'name':'alex','pwd':123},
    {'name':'jack','pwd':123},
]
login_list = {'username':None,'login':False}
username = input('请输入您的用户名:')
paswd = int(input('请输入您的密码:'))
def foo(func): # func = jd_index def test_one(*args,**kwargs): # jd_index(name) args='laiying' if login_list['username'] and login_list['login']: res = func(*args,**kwargs) # 4,func是foo的一个形式参数,这个形式参数对应的实际参数是jd_index这个函数 #所以现在所执行就是在调用jd_index这个函数 return res #将jd_index这个函数的执行结果返回给test_one,谁调用就返回给谁 for i in user_dic: if username == i['name'] and paswd == i['pwd']: login_list['username'] = username login_list['login'] = True print('恭喜您登录成功') result = func(*args,**kwargs) # 与(4)同理,运行jd_index return result else: print('您的用户名或者密码错误,请重新输入') return test_one # 2 将test_one这个函数名retrun给 foo

@foo # 1. 开始调用foo这个装饰器,并将调用foo装饰器的这个函数(jd_index),做为参数传给foo # jd_index = foo(jd_index) def jd_index(name): print('hi %s! 您好,欢迎您登录xx首页'%name) return '执行成功。哈哈哈哈哈哈哈' # 5 ,这个return的结果是jd_index这个函数的一个返回值 jd_index(username) # 3,执行jd_index()就等于在执行foo()(),因为在第一步@foo的时候jd_index = foo(jd_index),相当于             #foo这个函数的执行结果从新赋值给了jd_index,所以现在执行jd_index,其实在执行foo这个函数的一个执行结果,而这个             #foo的执行就是return test_one 这个返回的test_one函数的内存地址,所以现在执行的就是test_one这个函数的内存地址,             #就是在执行test_one这个函数了 @foo def america(): print('----欧美专区----') america() @foo def japan(): print('----日韩专区----') japan()

五,有参装饰器

 

 1 user_dic = [
 2     {'name':'laiying','pwd':123},
 3     {'name':'zcy','pwd':123},
 4     {'name':'alex','pwd':123},
 5     {'name':'jack','pwd':123},
 6 ]
 7 login_list = {'username':None,'login':False}
 8 username = input('请输入您的用户名:')
 9 paswd = int(input('请输入您的密码:'))
10 def auth(auth_type='file'):
11     def foo(func):  # func = id_index
12         def test_one(*args,**kwargs):  
13             if auth_type == 'file':
14                 if login_list['username'] and login_list['login']:
15                     res = func(*args,**kwargs)  
16                                                 
17                     return res 
18 
19                 for i in user_dic:
20                     if username == i['name'] and paswd == i['pwd']:
21                         login_list['username'] = username
22                         login_list['login'] = True
23                         print('恭喜您登录成功')
24                         result  = func(*args,**kwargs)  
25                         return result
26                 else:
27                     print('您的用户名或者密码错误,请重新输入')
28             elif auth_type == 'ldap':
29                 print('你现在选择的类型是日韩板块。。。')
30                 result = func(*args,**kwargs)
31                 return result
32             else:
33                 print('欢迎您选择大陆板块')
34                 result = func(*args, **kwargs)
35                 return result
36 
37         return test_one  
38     return foo
#auth(auth_type='file')就是在运行一个函数,然后返回foo,所以@auth(auth_type='file')
#就相当于@foo,只不过现在,我们的foo作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
39 @auth()  
41 def jd_index(name):
42     print('hi %s! 您好,欢迎您登录xx首页'%name)
43     return '执行成功。哈哈哈哈哈哈哈'  
44 jd_index(username) 
45 
49 
50 @auth(auth_type='file')
51 def america():
52     print('----欧美专区----')
53 
54 america()
55 @auth(auth_type='ldap')
56 def japan():
57     print('----日韩专区----')
58 japan()

 

posted @ 2016-12-08 14:48  LaniLai  阅读(330)  评论(0编辑  收藏  举报