• 装饰器


    闭包:在一个内部函数中对外部函数作用域(非全局作用域)的变量进行引用,那么内部函数就会被称为闭包。

    闭包需要满足如下3个条件:

    .存在于两个嵌套关系的函数中,并且闭包是内部函数;
    .内部函数引用了外部函数的变量(自由变量);
    .外部函数会把内部函数的函数名称返回。
    
    # 闭包函数的实例:outer是外部函数 a和b都是外函数的临时变量
    def outer( a ):
        b = 10
        def inner():        # inner是内函数
            print(a+b)      #在内函数中 用到了外函数的临时变量
        return inner        # 外函数的返回值是内函数的引用
    
    if __name__ == '__main__':
        
        demo = outer(5)
        demo() # 15
        demo2 = outer(7)
        demo2() #17
        '''
        解析:
        在这里我们调用外函数传入参数5
        此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
        外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
        '''
    

    装饰器本质上是一个python函数,可让其他函数不做任何代码变更前提下增加额外功能,装饰器的返回也是一个函数。

    .装饰器是个嵌套函数
    .内部函数是一个闭包。
    .外部函数接收的是被修饰的函数(func)
    
    def w1(func):
       print(‘正在装饰’)
        def inner():
            print(‘正在验证权限’)
            return inner()
    
    @w1
    def f1():
        print(’f1')
    

    切面需求场景:

    插入日志
    性能测试
    事务处理
    缓存
    权限校验
    ...
    

    多个装饰器:执行顺序:先执行@w2,后执行@w1

    @w1
    @w2
    def f1():
            print('---f1---')
    

    带参数的装饰器:带参数的装饰器函数特点为返回结果是装饰器

    def logging(level):
        def wrapper(func):
            def inner_wrapper(*args, **kwargs):
                print("[{level}]: enter function {func}()".format(level=level,func=func.__name__))
                return func(*args, **kwargs)
            return inner_wrapper
        return wrapper
    
    @logging(level='INFO')
    def say(something):
        print("say {}!".format(something))
        # 如果没有使用@语法,等同于
        # say = logging(level='INFO')(say)
    
    @logging(level='DEBUG')
    def do(something):
        print("do {}...".format(something))
    
    if __name__ == '__main__':
        say('hello')
        do("my work")
    '''
    结果:
    [INFO]: enter function say()
    say hello!
    [DEBUG]: enter function do()
    do my work...
    解析:
    当带参数的装饰器被打在某个函数上时,比如@logging(level='DEBUG'),它其实是一个函数,会马上被执行,只要这个它返回的结果是一个装饰器时,那就没问题。
    '''
    

    基于类实现的装饰器

    class logging(object):
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            print("[DEBUG]: enter function {func}()".format(func=self.func.__name__))
            return self.func(*args, **kwargs)
    @logging
    def say(something):
        print("say {}!".format(something))
    
    '''
    解析:
    1、构造函数__init__里接受函数
    2、重载__call__方法(返回函数)
    '''
    

    带参数的类装饰器

    class logging(object):
        def __init__(self, level='INFO'):
            self.level = level
    
        def __call__(self, func):  # 接受函数
            def wrapper(*args, **kwargs):
                print("[{level}]:enter function {func}()".format(level=self.level, func=func.__name__))
                func(*args, **kwargs)
            return wrapper  # 返回函数
    
    @logging(level='INFO')
    def say(something):
        print("say {}!".format(something))
    '''
    解析:
    1、构造函数__init__里接受参数,非函数
    2、重载__call__方法(接受函数并返回函数)
    '''
    

    内置装饰器

    特性装饰器:@property  
    类方法装饰器: @classmethod
    静态方法装饰器:@staticmethod
    

    特性装饰器:@property 可以把一个实例方法变成其同名属性,以支持实例访问,它返回的是一个property属性

    import math
    class Circle:
        def __init__(self,radius): #圆的半径radius
            self.radius=radius
    
        @property
        def area(self):
            return math.pi * self.radius**2 #计算面积
    
        @property
        def perimeter(self):
            return 2*math.pi*self.radius #计算周长
    
    circle=Circle(10)
    print(circle.radius)#常规方式访问类中属性
    print(circle.area)  #通过@property访问方法area/perimeter,会触发area函数的执行,返回面积值
    print(circle.perimeter)
    

    property对象还具有setter、deleter 可用作装饰器

    setter: 设置属性值
    deleter:删除属性值
    getter: 获取属性值(实际使用可直接使用property获取)
    
    class C:
        def __init__(self):
            self._x = None
        @property
        def x(self):
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    
    c = C() # 实例化类
    c.x = 100 # 为属性进行赋值
    print(c.x) # 输出属性值,相当于使用getter方法
    del c.x # 删除属性
    

    类方法装饰器: @classmethod

    @classmethod修饰的方法不需要实例化和self参数,但第一个参数为表示类自身的cls参数,可以用来调用类属性,类方法,实例化对象等

    class A():
        number = 10
        @classmethod
        def get_a(cls):     #cls 接受类A,类A传入到被修饰的方法
            print('这是类本身:',cls)# 如果子类调用,则传入的是子类
            print('这是类属性:',cls.number)
    class B(A):
        number = 20
        pass
    
    A.get_a()# 调用类方法 不需要实例化可以直接调用类方法
    B.get_a()
    

    静态方法装饰器:@staticmethod

    import time
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        @staticmethod
        def now(): #用Date.now()产生当前时间实例
            t=time.localtime() #获取结构化的时间格式
            return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
        @staticmethod
        def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
            t=time.localtime(time.time()+86400)
            return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
    a=Date('1987',11,27) #自己定义时间
    print(a.year,a.month,a.day)
    b=Date.now() #采用当前时间
    print(b.year,b.month,b.day)
    c=Date.tomorrow() #采用明天的时间
    print(c.year,c.month,c.day)
    '''
    解析: @staticmethod改变一个方法为静态方法
    1、静态方法把某个普通函数归属于类对象 Date.now()和Date.tomorrow()为当前和明天时间实例
    2、静态方法本质为普通函数,因此,第一个形参没有特殊含义和要求。
    2、静态方法可以被类对象所调用,语法格式为:类对象.方法名([实参])或cls.方法名([实参])
    '''
  • 相关阅读:
    Linux内核学习第五周 系统调用
    Linux内核学习第三周 Linux启动过程分析
    WebStorm快捷键大全
    PAT乙级-1056. 组合数的和(15)
    PAT乙级-1043. 输出PATest(20)
    PAT乙级-1021.个位数统计(15)
    PAT乙级-1036.跟奥巴马一起编程(15)
    学习笔记-C++ STL iterator与对指针的理解-20170618
    学习笔记-Little Tips_day20170615-" " and ' '
    HTML5离线存储和本地缓存
  • 原文地址:https://www.cnblogs.com/txdblog/p/15893826.html
Copyright © 2020-2023  润新知