• Python函数-装饰器


    装饰器的深入

    1. 装饰器的使用法则

    开放封闭原则:

      1.对扩展是开放的

        为什么要对扩展开放呢?

        我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

      2.对修改是封闭的

        为什么要对修改封闭呢?

        就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

    装饰器完美的遵循了这个开放封闭原则。

    2. 装饰器的主要功能和装饰器的固定结构

    装饰器的主要功能

    在不改变函数调用方式的基础上在函数的前、后添加功能。

    装饰器的固定格式

    def timer(func):
        def inner(*args,**kwargs):
            '''执行函数之前要做的'''
            re = func(*args,**kwargs)
            '''执行函数之后要做的'''
            return re
        return inner

    装饰器的固定格式wraps版--后续了解

    from functools import wraps
    
    def deco(func):
        @wraps(func) #加在最内层函数正上方
        def wrapper(*args,**kwargs):
            return func(*args,**kwargs)
        return wrapper
    
    装饰器的固定格式——wraps版

    3. 装饰器基础需求-计算一个函数的运行时间

    见博文

    http://www.cnblogs.com/wangph/p/8875544.html

    计算一个函数的运行时间
    import time
    def timmer(f):
        def inner(*args,**kwargs):
            start_time = time.time()
            ret = f(*args,**kwargs)
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return inner
    
    @timmer   # func = timmer(func)
    def func(a,b):
        print('begin func',a)
        time.sleep(0.1)
        print('end func',b)
        return True
    
    ret = func(1,2)   #--> inner()
    
    
    def timmer(f):
        def inner(*args,**kwargs):
    
            ret = f(*args,**kwargs)
    
            return ret
        return inner

    4. 装饰器进阶需求

    4.1 确认是否启用装饰器-装饰器的参数

    如何确认你的装饰器是否生效呢?最好的方式 是传参决定

    我们的方法是,在原装饰器的外层,再加一层函数,然后return原装饰器的函数名。

    之后在装饰器内层函数中加判断,确认参数的质量是否生效。

    import time
    
    FLAG = True
    def outer(flag):   #在装饰器timmer的外层加outer函数,接收传参 flag
        def timmer(f):
            def inner(*args,**kwargs):
                if flag == True:        ##在装饰器的中的内层函数inner中判断传参,确认装饰器是否生效
                    start_time = time.time()
                    ret = f(*args,**kwargs)
                    end_time = time.time()
                    print(end_time - start_time)
                else:
                    ret = f(*args, **kwargs)
                return ret
            return inner
        return timmer  # outer函数中返回装饰器的函数名timmer
    
    @outer(FLAG)   # func = timmer(func)    #调用装饰器,调用outer即可,在后面加实参
    def func(a,b):
        print('begin func',a)
        time.sleep(0.1)
        print('end func',b)
        return True
    
    func(1,2)

    4.2 一个函数使用多个装饰器来装饰

    eg:一个函数需要同时使用确认登录和计算运行时间的装饰器

    现在我已经有了如下两个装饰器和一个函数,那么我们如何调用这两个装饰器对着一个函数进行装饰呢?

    import time
    login_info = {'alex':False}
    def login(func):   # manager
        def inner(name):
            if login_info[name] != True:
                user = input('user :')
                pwd = input('pwd :')
                if user == 'alex' and pwd == 'alex3714':
                    login_info[name] = True
            if login_info[name] == True:
                ret = func(name)     # timmer中的inner
                return ret
        return inner
    
    def timmer(f):
        def inner(*args,**kwargs):
            start_time = time.time()
            ret = f(*args,**kwargs)     # 调用被装饰的方法
            end_time = time.time()      #
            print(end_time - start_time)
            return ret
        return inner
    
    
    def index(name):
        print('欢迎%s来到博客园首页~'%name)

    使用多个装饰器的方法

    使用方法一:

    @timmer
    @login
    def index(name):
        print('欢迎%s来到博客园首页~'%name)

    执行结果

    user :alex
    pwd :alex3714
    欢迎alex来到博客园首页~
    6.77495002746582

    使用方法二:

    @login
    @timmer
    def index(name):
        print('欢迎%s来到博客园首页~'%name)

    执行结果呢

    user :alex
    pwd :alex3714
    欢迎alex来到博客园首页~
    3.0994415283203125e-05

    我们发现两种调用装饰器的方法差异是:两个装饰器的上下顺序不相同。

    返回的结果是第二张方法timmer计算了函数index的执行时间,而第一个方法timmer则计算了index的执行时间和装饰器login的运行时间

    由此我们可以发现,使用装饰器的时候,装饰器对它正下方挨着的函数(装饰器)生效 !


    其中的函数执行关系我们可以通过下面一段代码来了解

    def wrapper1(func):
        def inner1():
            print('wrapper1 ,before func')
            func()
            print('wrapper1 ,after func')
        return inner1
    
    def wrapper2(func):
        def inner2():
            print('wrapper2 ,before func')
            func()
            print('wrapper2 ,after func')
        return inner2
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')
    
    f()

    让我们来看一下这段函数的执行返回结果

    wrapper2 ,before func
    wrapper1 ,before func
    in f
    wrapper1 ,after func
    wrapper2 ,after func

    我们来看图分析下当函数f使用了两个装饰器的时候,它的执行过程:

    '''
    根据上面的分析,当f调用两个装饰器的时候,首先执行的是最上面装饰器的内层函数 iunner2
    这时候到了执行阶段
    执行inner2 第一步 print('wrapper2 ,before func')
            第二步  func() = inner1() 
                            执行inner1的第一步 print('wrapper1 ,before func')
                                    第二步 func() = f
                                            执行 f中的主函数     print('in f')
                                    第三步 执行 inner1的  print('wrapper1 ,after func')
            第三步  func() = inner1()  inner()1执行完了,func()就执行完了。继续往下走 执行 print('wrapper2 ,after func')
    函数执行结束
    
    在这个过程中要注意语法糖中的变量指向和装饰器中func接收的实参变化 
                                                                                          
    '''
    

     

  • 相关阅读:
    个人学习jQuery笔记
    (转载) jQuery页面加载初始化的3种方法
    [转]学会和同事相处的30个原则
    解决iis出现这个问题-2147467259 (0x80004005)
    不规则瀑布流图片墙
    实现图片大小的自动控制( 图片大小控制CSS代码)
    (转载)DataTable使用技巧总结
    (转载) jQuery 页面加载初始化的方法有3种
    ajax连接数据库并操作数据库
    java Semaphore实现ABC三个线程循环打印
  • 原文地址:https://www.cnblogs.com/wangph/p/8932534.html
Copyright © 2020-2023  润新知