Python装饰器用法介绍
本文主要介绍Python装饰器的使用方法及其功能。在Python编程中,装饰器是一项非常强大的功能,可以节省代码,同时可以实现多种目的。我们将从以下几个方面对Python装饰器进行详细的阐述。
1、装饰器是什么
装饰器是Python函数的一个重要概念。可以理解为在一个函数外部添加另一个函数,以对原函数进行一些修改或增强功能。装饰器常常用于日志打印、性能测试、授权验证、缓存等场景。
2、装饰器的基本用法
装饰器通常以@符号表示,在函数定义前使用。如下所示:
@decorator def func_name(): pass
其中,decorator为装饰器函数名,func_name是待装饰的函数名。在函数运行时,装饰器会先于函数执行。
下面是一个简单的装饰器示例,用于输出函数执行时间:
import time def time_cal(func): def wrapper(): start_time = time.time() func() end_time = time.time() print("花费时间:", end_time - start_time, "秒") return wrapper @time_cal def hello(): print("Hello world!")
上述代码中,time_cal是计时装饰器函数,wrapper函数记录函数开始和结束时间,hello为待装饰的函数。在@time_cal下,调用hello函数时,会先运行wrapper函数,记录执行时间,接着调用hello函数输出”Hello world!”。
缓存装饰器可以缓存函数的结果,以便在下次调用时直接获取,而不必重新执行函数。这对于复杂且耗时的函数尤其有用。下面是一个例子:
import functools def cache(func): cached = functools.lru_cache(maxsize=None) @functools.wraps(func) def wrapper(*args, **kwargs): return cached(*args, **kwargs) return wrapper @cache def fib(n): if n < 2: return n return fib(n-1) + fib(n-2)
上述代码中,cache为缓存装饰器函数,使用了functools模块的lru_cache方法。在调用fib函数时,如果已经计算过fib(n)的值,则直接从缓存中获取;否则,执行fib(n)并将结果缓存起来。
日志装饰器可以用于记录函数的执行情况,比如输入参数、输出结果以及程序错误等。下面是一个简单的日志装饰器:
def log(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"[INFO]: {func.__name__} start") result = func(*args, **kwargs) print(f"[INFO]: {func.__name__} end") return result return wrapper @log def add(a, b): return a + b
在使用@log装饰器后,执行add函数时,会先打印函数名称和执行开始时间,接着输出函数结果,并打印执行结束时间。
装饰器函数可以被替换成一个装饰器类,使其具有更多的灵活性和可配置性。下面是一个装饰器类的例子:
class Cache: def __init__(self, func): self.func = func self.cache = {} def __call__(self, *args): if args in self.cache: return self.cache[args] else: result = self.func(*args) self.cache[args] = result return result @Cache def fib(n): if n < 2: return n return fib(n-1) + fib(n-2)
上述代码中,Cache类实现了一个简单的缓存装饰器,和上一篇缓存装饰器不同之处在于函数被封装在类里面,而不是在函数内。
在Python中,可以同时使用多个装饰器对函数进行修饰。装饰器的执行顺序与装饰器定义顺序相反。下面是一个双重装饰器:
def log(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"[INFO]: {func.__name__} start") result = func(*args, **kwargs) print(f"[INFO]: {func.__name__} end") return result return wrapper def cache(func): @functools.lru_cache(maxsize=None) @log def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @cache def fib(n): if n < 2: return n return fib(n-1) + fib(n-2)
上述代码中,cache装饰器使用了另一个装饰器log,在每次函数执行前打印日志信息。
装饰器会改变函数的调用方式,比如参数列表、返回值类型等。为了不影响函数使用,需要在装饰器中添加functools.wraps(func)语句,保留原函数的元信息。否则,在调用help()等函数时,可能会显示错误的函数签名。
Python支持装饰器嵌套,即装饰器可以使用其他装饰器,实现更多的功能。但是,装饰器嵌套深度不能过大,否则会导致代码可读性下降和调试难度增加。
对于不需要修改原函数的装饰器,也可以不添加括号。比如在使用flask框架时,@app.route可以不加括号,直接使用。
本文主要介绍了Python装饰器的定义、基本用法、应用场景和高级用法,以及注意事项。装饰器是Python中非常强大的功能,帮助我们实现多种任务,如缓存、日志、性能等。虽然装饰器在使用上比较灵活,但需要我们在实践中多加练习,才能充分发挥它的优势。