Python基础教程之装饰器详解
作者:陆理手记
众所周知,Python装饰器是一种常见的元编程特性,它提供了一种方便的方法来修改或增强现有函数的行为,而不需要修改函数的源代码,保持代码的可读性和可维护性。在本教程中,我们将深入探讨Python装饰器的基本概念、语法及其应用,并利用实际例子加深理解。
1.什么是装饰器模式
装饰器模式是一种允许在运行时动态地改变对象或类功能的技术。在Python中,装饰器实际是一种特殊的函数,装饰器函数接收一个函数作为参数,并返回一个修改后的函数,新函数具有与原始函数相同的名称和参数。在调用原始函数之前或之后,可执行一些额外的操作,如计时、日志记录或修改参数等。下面是一个简单的装饰器示例,它用于在函数调用前后显示信息。
def add_info(func): def wrapper(*args, **kwargs): print(f"Call function {func.__name__} with args {args} and kwargs {kwargs}") result = func(*args, **kwargs) print(f"Function {func.__name__} returned {result}") return result return wrapper @add_info def add(x, y): return x + y # 调用add函数 print(add(3, 5))
输出结果
Call function add with args (3, 5) and kwargs {}
Function add returned 8
8
在上述示例中,add_info
是一个装饰器函数,它定义了一个名为wrapper
的嵌套函数。在调用被装饰的函数add时,实际上会先执行add_info
函数,并传入add函数作为参数,然后将其返回的wrapper
函数作为修改后的add函数使用。在wrapper
函数内部,我们首先打印了一些调试信息,然后通过func(*args, **kwargs)
调用原始函数,并返回其返回值。因此,在调用add函数时,我们会对其输入输出进行了一些额外的监测和记录。
2.复合装饰器
除了上述示例中展示的基本装饰器模式之外,Python装饰器还有一些其他的高级用法,例如多个装饰器的复合、装饰器的参数传递、类装饰器等。下面再来看一下例子:
# 多个装饰器的复合 def hello(func): def wrapper(*args, **kwargs): print("Hello,") return func(*args, **kwargs) return wrapper def world(func): def wrapper(*args, **kwargs): print("World!") return func(*args, **kwargs) return wrapper @hello @world def greet(): print("How are you?") greet()
通过上述例子,我们可以实现使用多个不同的装饰器来组成函数的装饰链,每个装饰器负责一项特定的任务。
3.装饰器参数传递
我们还可以向装饰器传递参数,使其更加灵活,以适应不同的使用场景。
# 装饰器的参数传递 def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for i in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(3) def hi(name): print(f"Hi, {name}") hi("Alice")
输出:
Hi, Alice
Hi, Alice
Hi, Alice
在上述示例中,我们定义了一个装饰器工厂repeat
,它接收一个times
参数,并返回一个新的装饰器decorator
。在decorator
中,我们使用for循环来执行被装饰函数3次。这样,我们就可以为同一个函数应用多个不同的装饰器,以实现更加灵活的装饰器功能。
4.类装饰器
我们还可以使用类装饰器来实现更复杂的装饰器逻辑,除了上面介绍的函数装饰器,我们还可以将装饰器实现为类。实现装饰器类时,我们需要在该类中实现__init__()
和__call__()
方法。
# 类装饰器 class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("Do something before function execution") result = self.func(*args, **kwargs) print("Do something after function execution") return result @MyDecorator def my_func(): print("My function") my_func()
在上述示例中,我们定义了一个类MyDecorator来实现装饰器,其中__init__()
方法用于接收被装饰的函数my_func
,__call__()
方法用于实现装饰器的逻辑。与函数装饰器类似,我们可以在__call__()
方法中执行一些额外的操作,例如打印调试信息、记录日志等。
5.装饰器的实际用途
装饰器可用于许多实际用途,比如:
- 计时:测量函数执行时间;
- 日志记录:记录函数调用时的日志信息;
- 缓存:缓存函数的结果,以避免重复计算;
- 输入验证:检查函数参数是否符合预期。
以下是几个具体的示例。
1.用装饰器计时函数执行时间:
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__} took {end_time - start_time} seconds to run.") return result return wrapper @timer def slow_function(): time.sleep(2) slow_function()
输出:
slow_function took 2.0058863162994385 seconds to run.
2.用装饰器记录函数调用信息:
def logger(func): import logging loggingigasicConfig(filename="log.txt", level=logging.INFO) def wrapper(*args, **kwargs): logging.info(f"Function {func.__name__} was called with args={args} and kwargs={kwargs}.") result = func(*args, **kwargs) logging.info(f"Function {func.__name__} returned {result}.") return result return wrapper @logger def add(a, b): return a + b add(3, 5)
这个例子中,我们在wrapper函数中使用Python的日志模块记录函数调用信息和返回结果。我们可以在一个名为log.txt的文件中看到输出。
3.用装饰器实现输入验证:
def validate_inputs(func): def wrapper(*args, **kwargs): for arg in args: if noteisinstance(arg, int): raise TypeError("All arguments must be integers.") for value in kwargs.values(): if noteisinstance(value, int): raise TypeError("All keyword arguments must be integers.") return func(*args, **kwargs) return wrapper @validate_inputs def sum_numbers(a, b, c): return a + b + c sum_numbers(1, 2, 3) sum_numbers("1", "2", c=3) # This line will raise a TypeError.
这个装饰器用于验证函数的输入参数是否符合预期。如果有任何参数不是整数,装饰器将抛出TypeErrors异常。
6.总结
上一篇教程:Python基础教程:多线程编程
Python的装饰器模式是一种强大的技术,它可扩展函数的功能,而不需要在函数本身的代码中创建复杂的逻辑。通过使用装饰器,我们可以轻松地构建更复杂和功能强大的应用程序。在本教程中,我们介绍了Python装饰器的基本概念、语法及其应用,并举了一些实际例子,希望这些内容能够帮助您更深入地理解Python装饰器并应用于实际项目中。
以上就是Python基础教程之装饰器详解的详细内容,更多关于Python装饰器的资料请关注脚本之家其它相关文章!