装饰器的实现

1、装饰器介绍

1.1 装饰器的概念

      装饰器的本质就是函数,为其他函数添加附加功能。

import time
def cal(l):
    start_time=time.time()
    res=0
    for i in l:
        time.sleep(0.1)
        res+=i
    stop_time=time.time()
    print('函数的调用时机是%s' %(stop_time-start_time))
    return res
print(cal(range(100)))

如上程序,就是为cal(range(100)的计算添加了一个运算时间的功能。

1.2 装饰器的原则

 (1)不修改被修饰函数的源代码

 (2)不修改被修饰函数的调用方式

2、装饰器的知识储备

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

2.1 高阶函数

(1)函数接受的参数是一个函数名

def foo():
    print('from foo')
def test(func):
    print(func)
test(foo)

print(func)就是接受了一个函数名。

(2)函数的返回值是一个函数名

def foo():
    print('from the foo')
def test(func):           # func相当于foo
    return func

返回值报有func函数。

import time

def foo():
    time.sleep(0.1)
    print('from foo')
def test(func):              #func=foo
    start_time=time.time()
    print(func)
    func()
    stop_time=time.time()
    print('函数运行的时间是 %s' % (stop_time - start_time))
test(foo)           #修改了函数调用的方式

上述程序中,用到高阶函数是,修改了函数的调用方式,违背了装饰器的原则。

import time
def foo():
    time.sleep(0.2)
    print('来自foo')
# 不修改源代码
# 不修改foo的调用方式
def timmer(func):                # func=foo
    start_time = time.time()
    func()
    stop_time = time.time()
    print('函数运行的时间是 %s' % (stop_time - start_time))
    return func
foo=timmer(foo)
foo()     

运行结果是:

来自foo
函数运行的时间是 0.20316243171691895
来自foo

在不改变源代码和函数调用方式时,高阶函数的调用有多运行了一次。所以高阶函数自身满足不了装饰器的原则,必须要嵌套。

2.2 函数嵌套

def zushiye(name):
    print('from zushiye: %s' % name)
    def tudi():
        print('from zushiye')
        def chongsun():
            print('from chongsun')
        chngsun()
    tudi()
zushiye('黄药师')

函数嵌套就是函数里面有写入函数。

2.3 闭包

2.3.1 闭包的概念

   在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

2.3.1简单的理解

      (1,5) 是一个区间,但对这个区间做分析、计算什么的,经常会用到1和5这两个不属于这个区间的值,[1,5]就是(1,5)的闭包。

     在生活上,我们办事情,找A部门,A部门说,你先得找B部门盖个章,B部门说,你先得找C部门盖个章,C部门说,这个东西不是我们的职权范围…… 踢皮球,这就是非闭包。闭包就是负责到底,你找到A部门,A部门接待的那个人负责到底,他/她去协调B部门和C部门。

3、装饰器的实现

3.1装饰器的架子

import time
def timmer(func):           # func=test
    def wrapper():
        # print(func)
        start_time = time.time()
        func()                         #当前定义无func,往外去找
        stop_time = time.time()
        print('运行时间是%s' % (stop_time - start_time))

    return wrapper

@timmer                        #相当于test=timmer(test)
def test():
    time.sleep(0.3)
    print('test函数运行完毕')

test = timmer(test)
test()

3.2 装饰器中带上参数

一般为了防止在函数中将代码写死,在定义形参是用参数组:*args,**kwargs。

 1 import time
 2 def timmer(func):
 3     def wrapper(*args,**kwargs):
 4         start_time=time.time()
 5         res=func(*args,**kwargs)
 6         stop_time=time.time()
 7         print('运行时间是 %s' %(stop_time-start_time))
 8         return res
 9     return wrapper
10 
11 @timmer           # 相当于test=timmer(test)
12 def test(name,age):
13     time.sleep(0.4)
14     print('函数运行完毕,名字是[%s],年龄是[%s]'%(name,age))
15     return '这是test的返回值'
16 
17 res=test('czd',25)             #就是运行wrapper
18 print(res)
19 
20 @timmer           # 相当于test1=timmer(test1)
21 def test1(name,age,gender):
22     time.sleep(0.4)
23     print('函数运行完毕,名字是[%s],年龄是[%s],性别是[%s]'%(name,age,gender))
24     return '这是test的返回值'
25 
26 res=test1('cyz',22,'female')             #就是运行wrapper
27 print(res)

3.3 验证功能:以京东主页为例

 1 user_dic = {'username': None, 'login': False}
 2 
 3 
 4 def auth_func(func):
 5     def wrapper(*args, **kwargs):
 6         if user_dic['username'] and user_dic['login']:
 7             res = func(*args, **kwargs)
 8             return res
 9         username = input('用户名:').strip()
10         passwd = input('密码:').strip()
11         if username == 'czd' and passwd == '12345':
12             user_dic['username'] = username
13             user_dic['login'] = True
14             res = func(*args, **kwargs)
15             return res
16         else:
17             print('用户名或密码错误')
18 
19     return wrapper
20 
21 
22 @auth_func
23 def index():
24     print('欢迎来到京东主页')
25 
26 @auth_func
27 def home(name):
28     print('欢迎回家 %s' % name)
29 
30 @auth_func
31 def shopping_car(name):
32     print('购物车里有[%s,%s,%s]' % ('奶茶', '妹妹', '手机'))
33 
34 
35 index()
36 home('czd')
37 shopping_car('czd')

以上是学习完装饰器课程后的总结,才开始入门。希望各位大神指正。

原文地址:https://www.cnblogs.com/changzhendong/p/11195901.html