python中的装饰器(decorator)

本文深入探讨了Python中的装饰器和闭包概念。装饰器是一种利用闭包实现的功能增强工具,允许在不修改原有函数代码的情况下添加新功能。文章通过实例详细解释了闭包的创建和使用,以及装饰器的四种类型:无参无返回值、无参有返回值、有参无返回值和有参有返回值。此外,还介绍了如何使用多个装饰器以及创建万能装饰器的方法。最后,提到了通过类实现装饰器的可能性。
摘要由CSDN通过智能技术生成

0. 基础

在Python中,装饰器是在不改变已有函数的代码的前提下,给函数增加新的功能的一种函数。装饰器接收一个函数作为参数,返回值也是一个函数。(注:装饰器参数和返回值是固定的!)。在Python中,实现装饰器的方式叫做闭包

1. 闭包的实现

# 闭包
def outer_func():
    '''返回值是内部函数的引用'''
    a = 1
    # 内部函数
    def inner_func(b):
        nonlocal a
        a += b
        print(a)

    return inner_func


# 方式一
func = outer_func()  # 返回内部函数的引用
func(b=100)

# 方式二
print(outer_func()(b=200))

# 运行结果
101
201
None

闭包的重点

(1)外函数的内部定义了一个内函数。
(2)内函数使用了外函数的临时变量。
(3)外函数的返回值是内函数的引用。
在上面的代码中,外函数是outer_func,在它的内部有内函数inner_func,a是外函数的临时变量,在内函数中使用了a,外函数的返回值是内函数inner_func。如果在内部函数中直接使用外部函数的变量a(即,不改变a的值),直接使用就可以了;如果要修改a的值,需要将变量声明为nonlocal。内部函数可以接收参数,然后在内函数里使用参数。这里使用func接收outer_func()的返回值,返回值func是一个函数,相当于inner_func,给func()传入参数并执行,则会运行inner_func中的代码。也可以不使用变量来接收,而是在outer_func()后面直接传参并执行,后面有两个小括号:outer_func()(),第二个括号中传入内函数的参数。

2.装饰器

2.1 装饰器修饰一个函数

写装饰器–>写被装饰函数–>调用。

def func_name(func):
    def wrapper(*args, **kwargs):
        print("The func name is {}".format(func.__name__))
        return func(*args, **kwargs)
    return wrapper


@func_name
def func_one():
    print('This is function one.')

    
#
func_one()

# 运行结果
The func name is func_one
This is function one.

先执行装饰器中的内容,再执行被装饰函数。

2.2 一个装饰器修饰多个函数
def func_name(func):
    def wrapper(*args, **kwargs):
        print("The func name is {}".format(func.__name__))
        return func(*args, **kwargs)
    return wrapper


@func_name
def func_one():
    print('This is function one.')


@func_name
def func_two():
    print('This is function two.')


# 带有装饰器函数的调用
func_one()
func_two()

# 运行的结果
The func name is func_one.
This is function one.
The func name is func_two.
This is function two.

:装饰器是通过闭包的方式实现的,外函数接收一个函数作为外函数的临时变量,然后在内函数中执行这个函数。内函数将需要的参数接收进来并传给执行的函数,然后将执行结果返回。在内函数中,可以添加额外的功能的代码,这些额外的功能就是装饰器添加的功能。最后外函数将内函数返回。使用装饰器来装饰函数时,在被装饰的函数的前一行,使用**@函数名**的形式来装饰,则函数本身的功能正常实现,装饰器中添加的功能也实现了。如上面代码中打印被装饰函数的函数名。

2.3 多个装饰器同时装饰一个函数
def decorator_one(func):
    def wrapper(*args, **kwargs):
        print('decorator one start.')
        result = func(*args, **kwargs)
        print('decorator one end!')
        return result
    return wrapper


def decorator_two(func):
    def wrapper(*args, **kwargs):
        print('decorator two start.')
        result = func(*args, **kwargs)
        print('decorator two end!')
        return result
    return wrapper


@decorator_one
@decorator_two
def hello_python():
    print('hello python!')


# 函数的调用
hello_python()

# 运行结果
decorator one start.
decorator two start.
hello python!
decorator two end!
decorator one end!

:可以看到,当多个装饰器装饰同一个函数时,会是一个嵌套的装饰结果。也就是说,先执行完离函数近的一个装饰器,然后再用离函数远的装饰器来装饰执行结果。

2.4 万能装饰器

装饰器的外函数会接收一个函数(可以有参数也可以没有参数,可以有返回值也可以没有返回值)作为参数,这个函数将在内函数中执行。所以装饰器也分为四类:无参无返回值无参有返回值有参无返回值有参有返回值。是否有参数和返回值完全取决于被装饰的函数。但是,我们写装饰器的目的就是用一个装饰器来装饰不同的函数,所以要考虑装饰器的通用性。我们可以通过可变参数来实现一种可以用来装饰任何函数的装饰器,万能装饰器

def decorator_all(func):
    def wrapper(*args, **kwargs):
        print('add some coding.')
        return func(*args, **kwargs)  # 执行外部函数的中的参数函数
    return wrapper

使用这种装饰器,可以用来装饰任意函数,不管函数是否有参数,是否有返回值。

2.5 类装饰器

在Python中,也可以通过类的方式来实现装饰器,通过使用 __init__ __call__方法来实现。

class DecoratorClass(object):

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('class decorator')
        return self.func(*args, **kwargs)


@DecoratorClass
def func_three():
    print('This is func three.')


# 调用
func_three()

# 运行结果
class decorator
This is func three.

解释:在实现类装饰器的时候,使用__init__()方法来接收被装饰函数,使用__call__()方法来添加装饰器要实现的功能,并在__call__()方法中执行和返回被装饰函数。

Ref

参考文献1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值