【Python】装饰器在装什么
装饰器decorator,可以简单的说 是一个输入参数是函数,返回值也是函数的一个函数
在Python中,函数是什么?
在讲decorator之前,我们要先理清楚python的一些基础知识。第一件事就是函数是什么。可能有些人知道在python中的所有东西都是对象,都是object,函数也不例外。函数只是Python中的一个普通的object而已。函数对象具有可调用性(callable
),可以在程序中像其他对象一样被传入其他函数或作为返回值。
函数对象在Python中如何使用?
函数对象可以在Python中像普通变量一样被传入其他函数,并且可以作为返回值返回一个新的函数。例如,可以定义一个接受两个参数的函数,然后将它作为参数传递给另一个函数,并在该函数内部调用这个参数函数。
什么是decorator
,它如何运作?
装饰器(decorator
)是Python中的一个特殊语法糖,它本身是一个可调用的对象(callable)(通常是函数),可以用来修改其他函数的行为。
使用装饰器时,它会接收一个函数作为输入,并返回一个新的函数作为输出,这个新函数通常会实现一些额外的功能,比如计时、日志记录等。
import time
# 计时callable
def timeit(f):def wrapper(x):start = time.time()ret = f(x)print(time.time() - start)return retreturn wrapper
@timeit
def my_func(x):time.sleep(x)
my_func(1)
- 不太好理解?我们想象一下,其实这就等价于
my_func(1)
→ 实际调用 timeit(my_func)(1)
→ 执行 wrapper(1)
→ 在 wrapper 中:
1. 记录开始时间
2. 调用原 my_func(1)
3. 打印耗时
4. 返回 my_func 的结果
装饰器中的 wrapper
是一个闭包
,关于闭包朋友们可以看看此篇:【Python】闭包是什么包?闭包的底层实现机制-CSDN博客
装饰器是否只能用于单参数的函数?
装饰器不仅限于单参数函数,它可以用于任何数量参数的函数。通过使用*args
和**kwargs
,即变长函数参数,装饰器能够适应不同参数数量的函数。
import time
# 计时callable
def timeit(f):def wrapper(*args, **kwargs):start = time.time()ret = f(*args, **kwargs)print(time.time() - start)return retreturn wrapper@timeit
def add(x,y):return x + yprint(add(2,3))
是否存在带参数的装饰器?
带参数的装饰器在本质上也是通过增加一层函数调用来实现的。它首先计算带有参数的装饰器,并得到一个返回函数的新装饰器,然后用这个新装饰器去装饰目标函数,最终得到的结果是一个带有额外功能(由装饰器提供的)的新函数。
类装饰器这个词在不同场景下有什么不同的含义?类装饰器如何实际应用并起到装饰作用?
类装饰器这个词在不同环境下具有不同含义:
- 可以当做装饰器使用的类
- 能够装饰类的装饰器
这两个概念是正交的,一个是关于装饰器本身,另一个是关于装饰器要装饰的对象。类装饰器的应用示例中,将一个名为Timer
的类作为装饰器应用在add
函数上。通过类装饰器,原本的add
函数被转换为一个Timer
类的对象,并将add
函数作为参数传递给Timer
类的实例,从而实现对add
函数的行为进行包装和扩展。
类装饰器是否可以传递参数,如何实现?
类装饰器同样可以传递参数。例如,当需要在打印的时间前加上自定义前缀时,可以通过在装饰器中接收参数并在调用类实例时将这些参数传递给目标函数来实现。
如何理解装饰器语法糖背后的等价形式?
装饰器语法糖的等价形式是指,对于一个类作为装饰器的情况,可以理解为:
- 类对象被实例化
- 将目标函数作为参数传入类的实例中
- 最终得到一个可调用的对象
该对象执行时会先执行原函数,再添加额外的行为(如计时等)。
真正的类装饰器是如何工作的?
真正的类装饰器是一个输入是类、返回也是类的函数,它通过重载类的字符串表示(如__str__
方法),在不改变原有类定义的前提下,对类的行为进行修改。这样,任何自定义类只需添加此类装饰器,就能方便地打印出类中数据成员的信息,有助于调试和理解类的行为。