Python装饰器(Decorator)可以在不更改原函数源代码的情况下,为函数添加一些额外的功能,是Python中非常重要的概念之一。本文将详细讲解Python装饰器的使用方法及实现过程。
1. 装饰器实现原理
在Python中,函数是一等公民,可以被当做变量、参数、返回值来使用。因此,Python装饰器就是利用函数作为对象,实现在不更改原有代码的情况下为函数添加额外功能的方法。
装饰器的基本语法如下:
@decorator_func
def func():
pass
其中,decorator_func
是一个接收函数作为参数的函数,它会在原函数func
执行之前或之后执行一些自己的代码,从而实现对原函数的装饰。
2. 装饰器示例
2.1. 给函数添加计时器功能
给函数添加计时器功能,可以统计函数执行时间,示例代码如下:
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Time elapsed: {end_time - start_time:.2f} seconds")
return result
return wrapper
@timer
def my_func():
time.sleep(2)
print("Hello, world!")
my_func()
在上面的代码中,timer
是一个装饰器函数,它接收一个函数func
作为参数,返回一个新的函数wrapper
,这个新函数会在原函数执行之前记录开始时间并在执行之后记录结束时间,并输出总共执行时间。
2.2. 给函数添加缓存功能
给函数添加缓存功能,可以避免反复计算相同的结果,提高函数执行效率,示例代码如下:
def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def fibonacci(n):
if n in (0, 1):
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(20))
在上面的代码中,memoize
是一个装饰器函数,它接收一个函数func
作为参数,返回一个新函数wrapper
,这个新函数会在执行原函数时检查缓存中是否存在相同的参数,并返回缓存中的结果,如果没有则进行计算并把结果存入缓存中。在这个示例中,我们用memoize
装饰了一个计算斐波那契数列的函数fibonacci
,通过缓存已经计算过的数列来提高效率。
3. 装饰器的高级用法
3.1. 装饰器可以带参数
装饰器可以带参数,如下面的示例所示,我们可以给装饰器timer
添加一个参数unit
,用来指定时间单位:
def timer(unit="s"):
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
if unit == "s":
elapsed_time = end_time - start_time
elif unit == "ms":
elapsed_time = (end_time - start_time) * 1000
elif unit == "us":
elapsed_time = (end_time - start_time) * 1000000
else:
raise Exception("Unsupported unit")
print(f"Time elapsed: {elapsed_time:.2f} {unit}")
return result
return wrapper
return decorator
@timer(unit="us")
def my_func():
time.sleep(0.002)
print("Hello, world!")
my_func()
在上面的例子中,我们定义了一个带参数的timer
函数,它返回一个装饰器函数decorator
,这个装饰器函数接收一个函数func
作为参数,返回一个新函数wrapper
。在wrapper
函数中,根据传入的参数unit
来决定输出时间的单位。
3.2. 装饰器可以被链式使用
装饰器可以被链式使用,如下面的示例所示,我们定义两个装饰器logging
和auth_required
,通过@logging
和@auth_required
的组合来对一个函数进行装饰:
def logging(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args} {kwargs}")
result = func(*args, **kwargs)
print(f"Finished calling {func.__name__}")
return result
return wrapper
def auth_required(func):
def wrapper(*args, **kwargs):
if is_authenticated():
return func(*args, **kwargs)
else:
raise Exception("Authentication failed")
return wrapper
@logging
@auth_required
def my_func():
print("Hello, world!")
my_func()
在上面的例子中,logging
和auth_required
都是装饰器函数,我们用@logging
和@auth_required
的组合,先对函数进行身份验证(auth_required
),成功后打印日志(logging
)。
4.小结
本文介绍了Python装饰器的原理、基本语法和两个示例:给函数添加计时器功能和给函数添加缓存功能。此外,我们还介绍了装饰器的高级用法:装饰器可以带参数和被链式使用。
在实际开发中,装饰器是非常有用的工具,可以优雅地实现一些横切面的需求,比如日志记录、缓存、身份验证、权限控制等。希望本文对你理解Python装饰器有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Python 装饰器 - Python技术站