14、Python之装饰器

Python函数 / 2020-11-20

装饰器依赖知识点:

1、什么是装饰器

器即工具,多数情况下指的是函数;装饰指的是为其它代码添加额外的功能!Python装饰器可以对函数、类、方法进行加工处理,以达到某种目的!

2、为何要用装饰器

在线上业务环境中,一般情况下我们写好的代码是不会随便变更的,线上直接修改代码保不准你改的代码会有BUG或者引起连锁反应,影响业务的正常运转!但有时候又想在不改动源代码的前提下,为其新增功能,有没有办法实现呢?of course!

装饰器就能在不改动被装饰对象的源代码以及调用方式的前提下,为被装饰对象添加新功能的一种手段!

3、如何用装饰器

即闭包函数的运用!

我们先来定义个简单的算数函数,并调用得到结果!

def square_sum(a, b):
    return 5**a + 3**b
print(square_sum(3, 4))
# 执行得到结果
206

这个函数定义是只有算数功能,并没有打印结果功能,我们需要在不改动它源码的情况下给square_sum添加打印功能!

def square_sum(a, b):
    return 5**a + 3**b

def decorator(func):
    def print_str(a, b):
        print('输入值为:', a, b)
        print('计算结果为:', func(a, b))
    return print_str


square_sum = decorator(square_sum)
square_sum(3, 4)

# 执行得到结果
输入值为: 3 4
计算结果为: 206

在上面示例中,没有改动函数square_sum的代码,也没更改它的调用方式;对调用者来说,一切似乎照旧,实际运行结果却不一样了!看山是山,山却不是山!

上面的示例是个很简单的示例,但是每次装饰都得手动定义变量,这很不Python!因此有了个语法来自动完成调用装饰器,出来吧,“@”!

如下所示,只需要在被装饰对象定义之前,用@DECORATOR方式即可完成赋值操作!装饰器定义必须得在@调用之前,牢记Python先定义后使用!

def decorator(func):
    def print_str(a, b):
        print('输入值为:', a, b)
        print('计算结果为:', func(a, b))
    return print_str

@decorator
def square_sum(a, b):
    return 5**a + 3**b

square_sum(3, 4)

在这个例子中,@decorator相当于

square_sum = decorator(square_sum)

4、有参装饰器

在上面的例子中,装饰器@decorator默认被装饰对象为唯一的函数;但有时候因为某些原因,我们又需要更多的参数,又不能修改原有的参数(比如形参那里写的是*args和**kwargs);这时就需要再多包一层来传递参数了!仅需要在调用装饰器时跟上参数即可!

def de1(sanxi):
    def decorator(func):
        def print_str(a, b):
            print('输入值为:', a, b)
            print('计算结果为:', func(a, b))
            print('hello,', sanxi)
        return print_str
    return decorator

@de1('andy')
def square_sum(a, b):
    return 5**a + 3**b

square_sum(3, 4)
# 执行得到结果
输入值为: 3 4
计算结果为: 206
hello, andy

5、了解函数对象的属性

函数对象有个属性__name__,它可以显示函数的名称;__doc__显示注释信息!如果我们调用了装饰器,那么装饰器会覆盖被装饰对象的名称!Python提供了一个内置的工具包和装饰器可以实现这个功能!如下所示:

# 调用装饰器时(未调用工具包)
def decorator(func):
        def print_str(a, b):
            '''
            这是装饰器注释
            '''
            print('输入值为:', a, b)
            print('计算结果为:', func(a, b))
        return print_str

@decorator
def square_sum(a, b):
    '''
    这是被装饰对象注释
    '''
    return 5**a + 3**b

print(‘函数名称:’, square_sum.__name__)
print(‘函数注释:’, square_sum.__doc__)

# 执行得到结果
函数名称: print_str
函数注释: 
            这是装饰器注释

我们调用工具包来进一步伪装,让装饰器属性变得跟原函数一模一样!

from functools import wraps
def decorator(func):
    @wraps(func)
    def print_str(a, b):
        '''
        这是装饰器注释
        '''
        print('输入值为:', a, b)
        print('计算结果为:', func(a, b))
    return print_str

@decorator
def square_sum(a, b):
    '''
    这是被装饰对象注释
    '''
    return 5**a + 3**b

print('函数名称:', square_sum.__name__)
print('函数注释:', square_sum.__doc__)

# 执行得到结果
函数名称: square_sum
函数注释: 
    这是被装饰对象注释

6、总结

装饰器核心是“name binding”,即名称绑定关系!在Python项目中得到广泛运用,尤其是在编写程序框架中!必须要学会灵活使用它!

世间微尘里 独爱茶酒中