轻松理解Python--装饰器(Decorators)

本文详细介绍了Python中的装饰器如何在不改变原函数代码的情况下增加新功能,包括无参数和有参数装饰器的使用方法,以及如何通过`@装饰器`语法糖和打包/解包处理参数差异。

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

Python中有一种较为高级的语法叫做装饰器。顾名思义,装饰器就是在原有的基础上对其进行装饰,使其更加实用或者美观。在Python中,装饰器的作用定义为:在不改变原函数代码的前提下,给原函数增加新的功能。

我们来看下面这个例子:

def func():
    x = input()
    print(x)
    return 0

res = func()

我们定义了一个func函数,功能是从键盘输入一个值赋给x,然后输出这个值。现在func函数已经写好了,我们需要增加一个功能,就是在输入之前要给一个提示信息,告诉用户现在应该输入x的值了,在不改变原函数代码的情况下,这个问题该如何解决呢?

接下来会用到函数作为参数传递给另一个函数,不懂的小伙伴们可以参考:Python中将函数作为参数传递给函数-优快云博客

这个时候就非常符合我们装饰器的定义:在不改变原函数代码的情况下,增加原函数的功能。

def func():
    x = input()
    print(x)
    return 0

def printer(func_name):    #将原先的func函数作为参数传递给printer函数,形成闭包,不传会发生无限递归调用
    def wrapper():
        print("请用户输入:")
        fun = func_name()
        return fun
    return wrapper

func = printer(func)  
res = func()

具体原理是:我们定义了一个printer函数,接受func函数作为参数,接着我们在printer函数里面定义了一个wrapper函数,功能是先输出一个“请用户输入”的提示语,来满足我们最开始的要求,接着调用原始的func函数,并将结果存在fun中,接着返回的是一个函数对象fun。最外层返回的是wrapper函数对象。

当我们在执行func = printer(func)的时候,首先是把原始的func函数传递给printer函数,然后printer函数返回一个wrapper函数对象,相当于是对wrapper函数进行调用,当调用wrapper函数的时候,就会先输出一个“请用户输入:”的语句。紧接着会调用原始的func函数,把其结果存为fun,此时fun的值是0(因为原始的func返回值是0),但更重要的是fun也是一个函数对象,功能和原始func一样。然后返回这个fun,返回这个fun的时候就是对fun进行调用,就会执行一遍原始的func函数。所以执行完func = printer(func)的时候,func这个名字已经绑定到printer的这个函数对象上面去了。所以当我们res = func()的时候,就不是调用原始的func,而是调用新绑定的函数对象printer。而printer的功能就是先输出“请用户输入:”,在调用原始的func。这样就能达到我们最开始的要求。

为了简化这一过程,Python提供了一个语法糖(@函数名),当我们在一个函数上面写上@函数名的时候,Python就会帮我们自动执行func1 = func2(func1):

def func2(func1):
    pass

@func2
def func1():
    pass

等价于

def func2(func1):
    pass

def func1():
    pass

func1 = func2(func1)

有的小伙伴可能会说,这个装饰器的复杂程度太高,还不如直接在原函数里修改。其实不然,试想这样一个场景:有一万个输入函数,都需要你去添加一个提示语,那么你就需要对这一万个函数进行修改,如果使用装饰器,就可以很方便的实现这一诉求。

刚刚讲的是没有参数的函数装饰器。那么有参数,我们应该怎么做呢?

先想想有无参数的区别在哪?

其实最主要的是在我们之前定义的wrapper函数中,我们使用fun = func()这里的时候就没有给func()传参数,但是现在问题来了,如果我的func原本就需要参数,且多个func都需要加入修饰器,每个func的参数个数还不一样,那怎么办呢?

其实也很好处理,只需要使用Python的打包和解包即可实现,把原装饰器代码改为:


def printer(func_name):    
    def wrapper(*args,**kwargs):
        print("请用户输入:")
        fun = func_name(*args,**kwargs)    #打包与解包的使用
        return fun
    return wrapper

不是很理解打包与解包的可以参考:Python:*args与**kwargs的作用【打包与解包】-优快云博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值