Python闭包的连体婴:装饰器

本文深入讲解Python装饰器的概念与应用,包括如何通过装饰器简化闭包使用,多装饰器的组合使用,以及如何创建适用于不同参数数量的通用装饰器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰器是个啥

使用闭包可以在不修改源码的前提下,为现有函数添加新的功能。

使用装饰器和闭包结合,可以使访问方式更加简单,更加实用。

装饰器和闭包息息相关。

【实例】使用装饰器和闭包结合给函数增加日志功能

# 闭包的应用:实现日志功能
import time

def write_log(func):
    try:
        file = open('log.txt', 'a', encoding='utf-8')
        # 写入相关信息(访问的函数名称,访问的时间)
        file.write(func.__name__)
        file.write('\t')
        # 写入访问时间
        file.write(time.asctime())
        file.write('\n')

    except Exception as e:
        print(e.args)
    finally:
        # 关闭文件
        file.close()

# 定义闭包
def func_out(func):
    def func_in():
        write_log(func)
        func()
    return func_in

# 使用了装饰器,效果和在调用函数前func1 = func_out(func1)一样
@func_out
def func1():
    print('我是功能1')

@func_out
def func2():
    print('我是功能2')

if __name__ == "__main__":
    func1()
    func2()

运行结果:

func1 Tue Nov 1 10:49:17 2022
func2 Tue Nov 1 10:49:17 2022

很显然,装饰器可以更简化地使用闭包。只需要在原函数前面添加‘@闭包外函数名’就可以达到在执行函数之前写一句类似func1 = func_out(func1)调用闭包的语句,非常的方便。

【注意】装饰器的名称应该是闭包外部函数的名称

多装饰器的使用

【实例】不修改一个函数源代码的前提下,给返回的“西游记”增加书名号

# 定义闭包1
def func_out(func):
    print('闭包1开始装饰……')

    def func_in():
        return '《' + func() + '》' 
		# 给‘西游记’加书名号
    return func_in

# 定义闭包2
def func_out2(func):
    print('闭包2开始装饰……')

    def func_in():
        return '$' + func() + '$' 
		# 给‘西游记’加‘$’符号
    return func_in


@func_out2
# 相当于在执行函数之前先执行book_name = func_out2(book_name)
@func_out
# 同理book_name = func_out(book_name)
def book_name():
    return '西游记'

print(book_name())

运行结果:

闭包1开始装饰……
闭包2开始装饰……
《西游记》 《西游记》 《西游记》

在使用多装饰器的时候,最靠近被装饰函数的闭包执行,远离被装饰函数的闭包执行。

指定参数个数的装饰器

之前的装饰器都应用在原函数不涉及传参的情况,那么当原函数涉及传参的时候,应该如何设计装饰器呢?

【实例】指定参数个数的装饰器

# 定义新增功能
def add_func():
    print('我是新增的功能')

# 定义闭包
def func_out(func):
    def func_in(x, y):
        add_func()
        func(x, y)

    return func_in

@ func_out # 原函数使用装饰器
def test(a, b):
    print('a = {0} b = {1}'.format(a, b))

test(1, 2)

运行结果:

我是新增的功能
a = 1 b = 2

这里在定义闭包的时候,如果没有其他需求,可以将闭包的内函数func_in()的形参和其函数体里面用于运行原函数的对象func()的形参设置成对应原函数的形参个数,然后平行地传进实参即可,而对于其他形参数量不同的元函数,可以多写几个闭包,然后用装饰器执行。

思考:但是,似乎这种方式有点麻烦,如果所有函数都需要同样的新增功能,那岂不是要给所有形参数量不同的函数挨个写闭包?!有没有可以通用所有函数的装饰器呢?

通用装饰器

只需要在设置闭包的时候,把前面传参数的部分的形参由固定参数个数修改为可变参数:*args, **kwargs 即可。

【实例】通用装饰器适应所有参数数量的函数

# 定义新增功能
def add_func():
    print('我是新增的功能')

# 定义闭包
def func_out(func):
    def func_in(*args, **kwargs): # 使用可变参数
        add_func()
        func(*args, **kwargs) # 这里也需要可变参数

    return func_in

@func_out # 装饰不需要传参的函数
def test():
    print('原函数1')

@func_out # 装饰需要传递两个参数的函数
def test1(a, b):
    print('a = {0} b = {1}'.format(a, b))

@func_out # 装饰需要传递三个参数的函数
def test2(a, b, c):
    print('a = {0} b = {1} c = {2}'.format(a, b, c))

test()
test1(1, 2)
test2(1, 2, 3)

运行结果:

我是新增的功能
原函数1
我是新增的功能
a = 1 b = 2
我是新增的功能
a = 1 b = 2 c = 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nine_mink

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值