likes
comments
collection
share

Python基础教程:装饰器

作者站长头像
站长
· 阅读数 17

众所周知,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函数时,我们会对其输入输出进行了一些额外的监测和记录。

Python基础教程:装饰器

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. 装饰器的实际用途

装饰器可用于许多实际用途,比如:

  • 计时:测量函数执行时间;
  • 日志记录:记录函数调用时的日志信息;
  • 缓存:缓存函数的结果,以避免重复计算;
  • 输入验证:检查函数参数是否符合预期。

以下是几个具体的示例。

  • 用装饰器计时函数执行时间:
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.
  • 用装饰器记录函数调用信息:
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的文件中看到输出。

  • 用装饰器实现输入验证:
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装饰器并应用于实际项目中。