欢迎来到田晓东的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
扩大
缩小

装饰器

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

闭包需要满足如下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.方法名([实参])
'''

posted on 2022-02-15 09:53  匍匐的仰望者  阅读(37)  评论(0编辑  收藏  举报

导航