zoukankan      html  css  js  c++  java
  • 装饰器的实现

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

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

  • 相关阅读:
    基于springboot框架的博客系统
    告别并不遥远的儿时,抬眼期待未来
    Python微信公众号教程基础篇——收发文本消息
    华为云落地敏捷+DevOps,助力大企业高效能
    【nodejs原理&源码赏析(5)】net模块与通讯的实现
    华为云&华中大联合实验室,夺得2019ICDAR发票识别竞赛世界第一
    00034_类与对象
    php批量下载文件
    php批量下载图片
    asp.net批量下载文件
  • 原文地址:https://www.cnblogs.com/changzhendong/p/11195901.html
Copyright © 2011-2022 走看看