python装饰器简解

文章目录
Python中装饰器的使用
装饰器的定义
装饰器的使用
多个装饰器的调用


Python中装饰器的使用

在软件开发过程中,不同的阶段设计开发时会定义一些函数,而后期的开发过程中,希望扩展一些装饰这个函数的内容,即装饰器;举例如下

存在一个计算两个数相加的函数

def add(a , b):
    '''
        求任意两个数的和
    '''
    r = a + b
    return r

res = add(123,456)
print(res)

执行结果:
579

希望在执行这个计算前程序输出"计算开始…";计算时输出"计算结束…" 前提是不能改变原函数;如下所示

#定义一个函数,达到需求的设计
def new_add(a,b):
    print('计算开始~~~')
    r = add(a,b)
    print('计算结束~~~')
    return r

r = new_add(111,456)    
print(r)

执行结果
计算开始~~~
计算结束~~~
567

以上的设计虽然完成了需求,但是相对应的也带来了一些问题

如果要修改的函数过多,修改起来会比较麻烦

并且不方便后期的维护

并且这样做会违反开闭原则(OCP)

OCP: Open Control Principle 程序的设计,要求开放对程序的扩展,要关闭对程序的修改

为了解决这个问题,创建一个可以自动的生产函数

装饰器的定义

# 用于计算两个数相加
def add(a,b):
    r = a+b
    return r

    
# 用于计算两个数相乘
def mul(a,b):
    r = a*b
    return r


def decorators(fun):
    '''


        这是一个装饰器函数
        用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

        **参数:
            fun 要扩展的函数对象
    '''
    # 创建一个新函数
    '''
    *args 用于接收所有的位置参数
    **kwargs 用于接受所有的关键字参数
    '''
    def new_fun(*args,**kwargs):  #将参数装包成元组或字典
        print('计算开始...')
        # 调用被扩展的函数
        num = fun(*args,**kwargs) #将元组拆包成位置参数,将字典拆包成关键字参数
        print('计算结束...')
        # 返回函数的执行结果
        return num
    # 返回新函数 
    return new_fun**

# 调用
r = decorators(add) # 将装饰器函数的返回值函数,即内部的函数给到r
print(r) # r就是装饰器函数的内部函数的内存地址
res = r(123,456) # 向内部函数传参,相当于add(123,456)
print(res)



执行结果
<function decorators.<locals>.new_fun at 0x0000016AFFFB6950>
计算开始...
计算结束...
579

计算两个数相乘的情况,如下调用

扫描二维码关注公众号,回复: 15254862 查看本文章
r = decorators(add) 
print(r)
res = r(123,456)
print(res)
print('-'*30)
r = decorators(mul) 
print(r)
res = r(2,3)
print(res)

执行结果

<function decorators.<locals>.new_fun at 0x000001D00B7168C8>
计算开始...
计算结束...
579


------------------------------
<function decorators.<locals>.new_fun at 0x000001D00B716950>
计算开始...
计算结束...
6

可见,每次调用装饰器函数的内部函数时,分配的内存肯定是不一样的,传入的add、mul实参就是真实计算的函数内容

装饰器的使用

  • 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
  • 在开发中,我们都是通过装饰器来扩展函数的功能的
  • 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数

如下所示:函数装饰器的内容不变,只是在定义函数的时候加上@装饰器函数的名称即可

但是这样一来,装饰器就与函数实体进行了绑定,以后调用函数时都会携带装饰器

def decorators(fun):
    '''
        这是一个装饰器
        用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

        参数:
            fun 要扩展的函数对象
    '''
    # 创建一个新函数
    '''
    *args 用于接收所有的位置参数
    **kwargs 用于接受所有的关键字参数
    '''
    def new_fun(*args,**kwargs):  #将参数装包成元组或字典
        print('计算开始...')
        # 调用被扩展的函数
        num = fun(*args,**kwargs) #将元组拆包成位置参数,将字典拆包成关键字参数
        print('计算结束...')
        # 返回函数的执行结果
        return num
    # 返回新函数 
    return new_fun

# 对函数实体进行装饰
@decorators
def add(a,b):
    r = a+b
    return r
@decorators
def mul(a,b):
    r = a*b
    return r

# 调用
res = add(123,456)
print(res)

print('-'*30)
res = r(2,3)
print(res)



计算开始...
计算结束...
579
------------------------------
计算开始...
计算结束...
6

多个装饰器的调用

  • 可以同时为一个函数指定多个装饰器
  • 函数将会安装从内向外的顺序被装饰
def fn1(fun):
    def new_function(*args , **kwargs):
        print('fn1装饰~开始执行~~~~')
        result = fun(*args , **kwargs)
        print('fn1装饰~执行结束~~~~')
        return result      
    return new_function


def fn2(fun):
    def new_function(*args , **kwargs):
        print('fn2装饰~开始执行~~~~')
        result = fun(*args , **kwargs)
        print('fn2装饰~执行结束~~~~')
        return result      
    return new_function

@fn1
@fn2
def say_hello():
    print('大家好~~~')

say_hello()

由内到外的执行就是,以say_hello()函数的输出结果为中心,先使用fn2装饰器,然后使用fn1装饰器

执行结果

fn1装饰~开始执行~~~~
fn2装饰~开始执行~~~~
大家好~~~
fn2装饰~执行结束~~~~
fn1装饰~执行结束~~~~

改变顺序

@fn2
@fn1
def say_hello():
    print('大家好~~~')

say_hello()

执行结果
fn2装饰~开始执行~~~~
fn1装饰~开始执行~~~~
大家好~~~
fn1装饰~执行结束~~~~
fn2装饰~执行结束~~~~

猜你喜欢

转载自blog.csdn.net/weixin_44683255/article/details/111938774
今日推荐