代码改变世界

装饰器

2019-07-29 17:34  风e逸  阅读(75)  评论(0)    收藏  举报

装饰器定义:

  在不改变源程序代码和运行方式的前提下,为程序添加附加功能的函数。

装饰器的两大原则:

  1.不修改被装饰函数的源代码

  2.不修改被装饰函数的运行方式

装饰器的知识储备:

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

  a) 高阶函数:

    定义: 一个函数的参数是一个函数,或者返回值是一个函数,两者满足其一,这个函数就叫高阶函数。

 1 import time
 2 def foo():
 3     print('这是一个函数')
 4     time.sleep(0.3)
 5     return 0
 6 def test(func): # 用这个函数来测试foo函数的运行时间
 7     start_time = time.time()
 8     func()
 9     stop_time = time.time()
10     print('函数[%s]的运行时间为%s' %(func, (stop_time-start_time)))
11     return func
12 res = test(foo)
View Code

   b) 函数嵌套:

    定义:定义一个函数,函数的内部定义了另一个函数,这种情况叫做函数的嵌套。

 1 def taowa(num, name_1, name_2):
 2     print('您选择的是%s 层套娃' % num)
 3     print('外层套娃颜色是 %s' % name_1)
 4 
 5     def taowa_sec(num_c):
 6         print('第%s 层套娃的颜色是%s' %(num_c + 2, name_2))
 7 
 8     if num > 1:
 9         for i in range(num - 1):
10             taowa_sec(i)
11     return 0
12 
13 taowa(2, '', '绿')
14 
15 输出结果:
16 您选择的是2 层套娃
17 外层套娃颜色是 红
18 第2 层套娃的颜色是绿
View Code

装饰器的框架:

 1 def timer(func):
 2     def test():
 3         # print(func)
 4         start_time = time.time()
 5         func()
 6         stop_time = time.time()
 7         print('运行时间是%s' % (stop_time-start_time))
 8     return test
 9 def foo():
10     time.sleep(0.3)
11     print('我是一个函数')
12     return 0
13 foo = timer(foo) # foo储存的为test的地址
14 foo()

  # 装饰器其实是一种偷换概念的存在,对于用户来说,运行的方法和名称没变,在上面例子中,函数名为foo,运行方法为foo()。但对于程序来说,实际上foo对应的函数地址已经改变,此时调用foo()运行的是一个包含了原函数+附加功能的新的函数,即 test()。

python为了简化操作:提供了@ + 装饰器名的语法,来替代

foo = timer(foo) # foo储存的为test的地址

这一步的操作。
刚刚说过,由于偷换概念,因此执行foo()实际运行的是test(),那么对于函数来说,返回值已经由原来foo()得返回值改变为test()的返回值,为了同步返回值,
需要在装饰器函数中加上一步返回值操作。同时需要获取并为test()加上原函数的参数。
因此装饰器实际操作为:
import time

# 定义一个装饰器函数
def timer(func):
    def test(*args,**kwargs): # 拿到原函数的参数
        # print(func)
        start_time = time.time()
        res=func(*args,**kwargs) # 获取返回值,并传入参数
        stop_time = time.time()
        print('运行时间是%s' % (stop_time-start_time))
        return res #同步返回值
    return test

@ timer
def foo():  # 这个作为原函数
    time.sleep(0.3)
    print('我是一个函数')
    return 0

re=foo()
print(re)    

 装饰器的验证功能:

  装饰器函数可以为函数提供验证功能,可用于网站的登录验证。

 1 def yanzheng(func):
 2     def wrapp(*args, **kwargs):
 3         username = input('username:')
 4         passwd = input('password:')
 5         if username == 'xtzz' and passwd == 'abc':
 6             res = func(*args, **kwargs)
 7             return res
 8         else:
 9             print('用户名或密码错误')
10     return wrapp
11 
12 # 在下列函数中,应用装饰器提供验证功能
13     # 用户名:xtzz   密码:abc
14 def welcome():
15     print('欢迎')
16     
17 @yanzheng
18 def home(name):
19     print('%s 欢迎回家' %name)
20     
21 @yanzheng
22 def shopping_car(name):
23     print('%s 的购物车里有%s, %s, %s' %(name, 'aaa', 'bbb', 'ccc'))
24 
25 # 运行程序:
26 welcome()
27 home('xtzz')
28 shopping_car('xtzz')
View Code