跳转至

高级主题:装饰器

概述

在Python中,装饰器(Decorator)是一种强大的工具,它允许我们在不修改原始函数代码的情况下,增强或修改函数的行为。装饰器本质上是一个函数,它接受一个函数作为输入,并返回一个新的函数。装饰器通常用于日志记录、权限检查、性能测试等场景。

装饰器的基本概念

什么是装饰器?

装饰器是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数。这个新的函数通常会在调用原始函数之前或之后执行一些额外的操作。

为什么使用装饰器?

装饰器的主要优点是代码的可重用性和可维护性。通过使用装饰器,我们可以将通用的功能(如日志记录、权限检查等)从业务逻辑中分离出来,从而使代码更加简洁和易于维护。

装饰器的基本用法

示例1:简单的装饰器

让我们从一个简单的装饰器开始,它会在函数执行前后打印一些信息。

# 定义一个简单的装饰器
def simple_decorator(func):
    def wrapper():
        print("函数执行前")
        func()  # 调用原始函数
        print("函数执行后")
    return wrapper

# 使用装饰器
@simple_decorator
def say_hello():
    print("Hello, World!")

# 调用被装饰的函数
say_hello()

输出:

函数执行前
Hello, World!
函数执行后

解释: - simple_decorator 是一个装饰器函数,它接受一个函数 func 作为参数。 - wrapper 是一个内部函数,它在调用原始函数 func 之前和之后分别打印一些信息。 - @simple_decorator 是装饰器的语法糖,它等价于 say_hello = simple_decorator(say_hello)

示例2:带参数的装饰器

有时候我们需要装饰器能够接受参数。下面的示例展示了如何定义一个带参数的装饰器。

# 定义一个带参数的装饰器
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

# 使用带参数的装饰器
@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")

# 调用被装饰的函数
greet("Alice")

输出:

Hello, Alice!
Hello, Alice!
Hello, Alice!

解释: - repeat 是一个装饰器工厂函数,它接受一个参数 num_times,并返回一个装饰器 decorator。 - decorator 是一个装饰器函数,它接受一个函数 func 作为参数,并返回一个新的函数 wrapper。 - wrapper 函数会调用原始函数 func 多次,次数由 num_times 决定。

示例3:类装饰器

除了函数装饰器,Python还支持类装饰器。类装饰器通常用于更复杂的场景。

# 定义一个类装饰器
class ClassDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("类装饰器:函数执行前")
        result = self.func(*args, **kwargs)
        print("类装饰器:函数执行后")
        return result

# 使用类装饰器
@ClassDecorator
def say_goodbye():
    print("Goodbye, World!")

# 调用被装饰的函数
say_goodbye()

输出:

类装饰器:函数执行前
Goodbye, World!
类装饰器:函数执行后

解释: - ClassDecorator 是一个类装饰器,它通过 __init__ 方法接受一个函数 func 作为参数。 - __call__ 方法使得类的实例可以像函数一样被调用。在这个方法中,我们在调用原始函数 func 之前和之后分别打印一些信息。

练习题

练习1:简单的装饰器

编写一个装饰器 @uppercase,它将函数的返回值转换为大写。

def uppercase(func):
    def wrapper(*args, **kwargs):
        # 调用原始函数并获取返回值
        result = func(*args, **kwargs)
        # 将返回值转换为大写
        return result.upper()
    return wrapper

@uppercase
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))

预期输出:

HELLO, ALICE!

练习2:带参数的装饰器

编写一个装饰器 @repeat(num_times),它将函数重复执行指定的次数,并返回所有结果的列表。

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(num_times):
                results.append(func(*args, **kwargs))
            return results
        return wrapper
    return decorator

@repeat(num_times=4)
def say_hello():
    return "Hello!"

print(say_hello())

预期输出:

['Hello!', 'Hello!', 'Hello!', 'Hello!']

练习3:类装饰器

编写一个类装饰器 @Timer,它会在函数执行前后打印出执行时间。

import time

class Timer:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start_time = time.time()
        result = self.func(*args, **kwargs)
        end_time = time.time()
        print(f"函数 {self.func.__name__} 执行时间: {end_time - start_time} 秒")
        return result

@Timer
def slow_function():
    time.sleep(2)
    return "Done"

print(slow_function())

预期输出:

函数 slow_function 执行时间: 2.000123 秒
Done

总结

  • 装饰器 是一种高阶函数,它允许我们在不修改原始函数代码的情况下,增强或修改函数的行为。
  • 装饰器可以接受参数,这使得它们更加灵活和强大。
  • 除了函数装饰器,Python还支持类装饰器,类装饰器通常用于更复杂的场景。
  • 装饰器在日志记录、权限检查、性能测试等场景中非常有用。

通过掌握装饰器,你可以编写出更加模块化、可重用和易于维护的代码。希望本教程能帮助你理解并熟练使用装饰器!