Python 中的装饰器是什么?
我们时常会遇到一个非常强大的功能——装饰器。
简单来说,装饰器是一种在不修改原函数代码的情况下,动态地为函数或方法添加功能的方式。
对于我们这些程序员来说,它就像是给现有功能加上“外壳”,在不影响原始功能的基础上增强它。
说到这里,大家可能会觉得:“哎,听起来很高大上,但到底怎么用?”别急,咱们一起来看看。
什么是装饰器?
在Python中,装饰器实际上是一个函数。这个函数可以接收另一个函数作为参数,并在不修改原始函数的情况下,返回一个新的函数。
它的主要作用就是在函数的基础上,动态地添加一些额外的功能,比如日志记录、权限校验、性能测试等。
装饰器的基本结构
让我们用最简单的例子来理解装饰器。假设我们有一个普通的函数:
defsay_hello():
print("Hello, world!")
现在我们想在 say_hello 函数执行之前,打印一条日志。那么我们可以通过装饰器来实现这个需求。我们定义一个装饰器 log_decorator,它接受一个函数作为参数,并返回一个增强版的函数:
deflog_decorator(func):
defwrapper():
print("Executing function...")
func()
return wrapper
然后,我们就可以把 log_decorator 装饰器应用到 say_hello 函数上:
@log_decorator
defsay_hello():
print("Hello, world!")
这种写法的意思是,@log_decorator 就相当于把 say_hello 函数传给了 log_decorator,并将装饰后的函数替换了原来的 say_hello。
如果我们执行 say_hello(),就会看到以下输出:
Executing function...
Hello, world!
如你所见,我们通过装饰器成功地为 say_hello 函数添加了日志打印的功能。
装饰器的原理
装饰器的原理很简单,核心就是函数的传递和返回。
在 Python 中,函数是第一类对象,也就是说,函数可以作为参数传递给另一个函数,也可以作为返回值返回。这就为装饰器的实现提供了基础。
函数作为参数:装饰器会把目标函数作为参数传递给包装函数。 包装函数:包装函数可以修改目标函数的行为,甚至可以在目标函数之前或之后执行额外的操作。 返回新的函数:装饰器返回一个新的函数,这个新函数会替代原来的目标函数。
带参数的装饰器
我们刚才演示的装饰器没有接收任何参数,但实际上,装饰器也可以接受参数。让我们看一个例子,创建一个接受参数的装饰器。
假设我们需要一个装饰器,记录函数执行的时间。为了让装饰器更灵活,我们想要指定日志的前缀。下面是一个带参数的装饰器:
import time
deflog_with_prefix(prefix):
defdecorator(func):
defwrapper(*args, **kwargs):
print(f"{prefix} - Starting execution of {func.__name__}")
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{prefix} - {func.__name__} executed in {end_time - start_time} seconds")
return result
return wrapper
return decorator
@log_with_prefix("INFO")
defmy_function():
time.sleep(1)
print("Function executed!")
my_function()
这里,log_with_prefix 是一个带参数的装饰器,它返回一个装饰器函数 decorator,这个函数接受目标函数 func,并返回包装后的 wrapper 函数。
在 wrapper 函数内部,我们记录了函数执行的时间,并输出日志。
执行时,输出会是:
INFO - Starting execution of my_function
Function executed!
INFO - my_function executed in 1.00012 seconds
通过这种方式,我们就可以在不改变函数本身的情况下,动态地为它添加日志功能,而且我们可以自由控制日志的前缀。
装饰器的链式应用
你还可以将多个装饰器应用到一个函数上,这种方式被称为装饰器的链式应用。
多个装饰器会按照从上到下的顺序应用。
比如我们可以同时为一个函数添加日志记录和执行时间统计:
@log_decorator
@log_with_prefix("DEBUG")
defmy_function():
time.sleep(1)
print("Function executed!")
my_function()
执行时,会首先打印出 DEBUG 日志,再打印 Executing function...,然后是函数的执行输出。
装饰器的应用场景
日志记录:在函数执行前后,记录一些日志信息。 性能监控:测量函数的执行时间,记录性能数据。 权限检查:在函数执行前,检查用户是否有权限。 缓存机制:为函数结果添加缓存,避免重复计算。 函数计数:记录函数被调用的次数。
常见的装饰器
Python标准库提供了一些常用的装饰器,最常见的包括:
@staticmethod:用于定义静态方法。@classmethod:用于定义类方法。@property:用于定义只读属性。
面试题:装饰器的最优回答
问题:装饰器是什么?它是如何工作的?
最佳回答: 装饰器是Python中的一种设计模式,它本质上是一个函数,可以动态地为另一个函数添加功能,而无需修改被装饰函数的代码。
装饰器通常用于一些横切关注点,如日志记录、权限验证、性能监控等。
它的工作原理是:装饰器接收一个函数作为输入,返回一个新的函数。
这个新的函数通常会在执行被装饰函数之前或之后,添加一些额外的行为。
例如,我们可以使用装饰器在函数执行之前打印日志,或者在函数执行后计算时间。
装饰器可以是带参数的,也可以通过链式应用组合多个装饰器。
Python中的标准库也提供了几种常用的装饰器,如 @staticmethod 和 @classmethod。
装饰器的使用让代码更加简洁和灵活,并且使得我们能够遵循“开闭原则”(对扩展开放,对修改封闭)来编写更容易维护的代码。
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。