Python装饰器函数:如何使用装饰器改进函数
Python 装饰器是一种特殊的函数,它可以修改其他函数的行为。使用装饰器可以改进函数,同时也能够使代码更加具有可读性。
在 Python 中,函数和类都是对象,都可以作为参数传递给其他函数。因此,Python 装饰器就是一个接受函数对象作为参数的函数,返回一个新的函数对象。
以下是一个简单的装饰器示例:
def my_decorator(func):
def wrapper():
print("Before the function is called.")
func()
print("After the function is called.")
return wrapper
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello)
say_hello()
运行上述代码会输出:
Before the function is called. Hello! After the function is called.
在上面的例子中,my_decorator 是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数。wrapper 函数是一个内部函数,它包装了 say_hello 函数,添加了一些额外的逻辑。最后,函数对象 say_hello 被重新赋值,它指向了新的函数对象 wrapper。
在 Python 中,有一种更方便的方式来应用装饰器,即使用 @ 符号。以下是上面的示例代码使用 @ 符号的写法:
def my_decorator(func):
def wrapper():
print("Before the function is called.")
func()
print("After the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
这种写法可以更加方便地应用装饰器,不需要手动重新赋值函数对象。
接下来,我们会介绍如何使用装饰器来改进函数的行为。
### 给函数添加计时功能
有些时候,我们需要统计一个函数的运行时间。使用装饰器,我们可以方便地给函数添加计时功能。以下是一个计时装饰器的示例代码:
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} elapsed time: {(end_time - start_time):.4f} seconds")
return result
return wrapper
在上面的代码中,我们定义了一个计时装饰器 timer。它接受一个函数作为参数,使用 time 模块来计算函数的运行时间,并输出运行时间。最后,它返回原来的函数。
接下来,我们可以使用 @timer 装饰器来装饰需要计时的函数。以下是一个示例代码:
@timer
def fib(n):
if n <= 1:
return n
else:
return fib(n - 1) + fib(n - 2)
result = fib(30)
print(result)
在上面的代码中,我们使用 @timer 装饰器来装饰 fib 函数,它会计算 fib(30) 函数的运行时间,并输出结果。这个示例稍微有些耗时,大概需要等待一段时间才能得到计时结果。
### 给函数添加缓存功能
有些时候,我们会需要缓存函数的结果,以便在需要时快速获取到结果。使用装饰器,我们可以方便地实现缓存功能。以下是一个缓存装饰器的示例代码:
def cache(func):
cache_dict = {}
def wrapper(*args):
if args in cache_dict:
print("From cache")
return cache_dict[args]
else:
result = func(*args)
cache_dict[args] = result
print("New calculation")
return result
return wrapper
在上面的代码中,我们定义了一个缓存装饰器 cache。它使用一个字典来保存函数输入和输出之间的映射关系。当函数被调用时,如果输入已经在缓存中,就直接返回缓存结果;否则计算新结果,并将结果保存到缓存中。
接下来,我们可以使用 @cache 装饰器来装饰需要缓存的函数。以下是一个示例代码:
@cache
def fib(n):
if n <= 1:
return n
else:
return fib(n - 1) + fib(n - 2)
result = fib(30)
print(result)
在上面的代码中,我们使用 @cache 装饰器来装饰 fib 函数,它会缓存 fib(30) 函数的结果,并输出结果。由于斐波那契数列的递归计算非常耗时,使用缓存装饰器可以大大提高计算效率。
### 给函数添加日志功能
有些时候,我们需要记录函数的输入和输出,以便后续调试和分析。使用装饰器,我们可以方便地添加日志功能。以下是一个日志装饰器的示例代码:
def log(func):
def wrapper(*args, **kwargs):
args_str = ", ".join(repr(arg) for arg in args)
kwargs_str = ", ".join(f"{key}={repr(value)}" for key, value in kwargs.items())
signature = f"{func.__name__}({args_str}, {kwargs_str})"
result = func(*args, **kwargs)
print(f"{signature} -> {result}")
return result
return wrapper
在上面的代码中,我们定义了一个日志装饰器 log。它使用字符串拼接的方式记录函数的输入和输出,并输出日志信息。
接下来,我们可以使用 @log 装饰器来装饰需要记录日志的函数。以下是一个示例代码:
@log
def add(x, y):
return x + y
result = add(2, 3)
print(result)
在上面的代码中,我们使用 @log 装饰器来装饰 add 函数,它会记录 add(2, 3) 函数的输入和输出,并输出日志信息。
### 小结
Python 装饰器是一种非常有用的语言特性,它可以用来修改其他函数的行为,同时也能够使代码更加具有可读性。使用装饰器,我们可以方便地给函数添加计时、缓存、日志等功能,从而使代码更加模块化和可维护。
