Python装饰器:函数装饰器①

1,095 阅读5分钟

2024-07-09_175549.png

1. 引言

装饰器是 Python 中一个非常强大的工具,它允许我们以一种优雅的方式扩展和修改函数或方法的行为。通过装饰器,我们可以在不修改原始代码的情况下为函数添加额外的功能。本文将详细介绍 Python 中的函数装饰器,包括其定义、使用方式、应用场景,并通过一个综合详细的例子展示如何使用装饰器。

2. 装饰器的基本概念

装饰器本质上是一个返回函数的函数。它接受一个函数作为参数,并返回一个增强后的函数。在 Python 中,装饰器通常通过 @ 符号来使用。装饰器可以用来修改函数的行为,而不需要改变函数的代码。

2.1. 装饰器的定义和使用

一个简单的装饰器的定义如下:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

我们可以使用 @ 符号将装饰器应用到一个函数上:

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

运行上述代码,输出结果为:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

在这个例子中,my_decorator 是一个装饰器,它接受函数 say_hello 作为参数,并返回一个新的函数 wrapper。当调用 say_hello 时,实际上调用的是 wrapper 函数。

2.2 带参数的装饰器

装饰器不仅可以装饰无参数的函数,还可以装饰带参数的函数。我们需要在内部函数 wrapper 中添加相应的参数,并在调用被装饰函数时传递这些参数。例如:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        result = func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result
    return wrapper

@my_decorator
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")

运行上述代码,输出结果为:

Something is happening before the function is called.
Hello, Alice!
Something is happening after the function is called.

2.3 带参数的装饰器函数

有时,我们希望装饰器本身能够接受参数。要实现这一点,我们可以定义一个返回装饰器的函数。例如:

def my_decorator_with_args(text):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print(f"{text} before the function is called.")
            result = func(*args, **kwargs)
            print(f"{text} after the function is called.")
            return result
        return wrapper
    return my_decorator

@my_decorator_with_args("Custom message")
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")

运行上述代码,输出结果为:

Custom message before the function is called.
Hello, Alice!
Custom message after the function is called.

在这个例子中,my_decorator_with_args 是一个接受参数的装饰器函数,它返回一个实际的装饰器 my_decorator

3. 常见的装饰器应用场景

装饰器在实际开发中有很多应用场景,下面是几个常见的例子:

3.1 日志记录

装饰器可以用来记录函数的调用日志,包括函数的输入参数和返回值。例如:

def log(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with arguments {args} and {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper

@log
def add(a, b):
    return a + b

add(2, 3)

运行上述代码,输出结果为:

Calling add with arguments (2, 3) and {}
add returned 5

3.2 访问控制

装饰器可以用来控制函数的访问权限,例如检查用户是否具有调用函数的权限。

def require_permission(permission):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if not has_permission(permission):
                print(f"Permission denied: {permission}")
                return None
            return func(*args, **kwargs)
        return wrapper
    return decorator

def has_permission(permission):
    # 假设有一个实际的权限检查逻辑
    return permission == "admin"

@require_permission("admin")
def delete_user(user_id):
    print(f"User {user_id} deleted")

delete_user(123)  # 有权限时执行函数

运行上述代码,输出结果为:

User 123 deleted

3.3 缓存

装饰器可以用来缓存函数的返回结果,以提高性能。例如:

def cache(func):
    cached_results = {}
    def wrapper(*args):
        if args in cached_results:
            return cached_results[args]
        result = func(*args)
        cached_results[args] = result
        return result
    return wrapper

@cache
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(35))

使用缓存装饰器后,计算斐波那契数列的速度将显著提高。

4. 综合示例

我们将通过一个综合示例来展示如何使用装饰器。这个示例将包含一个日志记录装饰器、一个权限检查装饰器和一个缓存装饰器。示例代码如下:

import time

def log(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with arguments {args} and {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper

def require_permission(permission):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if not has_permission(permission):
                print(f"Permission denied: {permission}")
                return None
            return func(*args, **kwargs)
        return wrapper
    return decorator

def has_permission(permission):
    return permission == "admin"

def cache(func):
    cached_results = {}
    def wrapper(*args):
        if args in cached_results:
            return cached_results[args]
        result = func(*args)
        cached_results[args] = result
        return result
    return wrapper

@log
@require_permission("admin")
@cache
def expensive_computation(x):
    time.sleep(2)  # 模拟耗时计算
    return x * x

# 测试综合示例
print(expensive_computation(3))
print(expensive_computation(3))  # 第二次调用时应使用缓存

运行上述代码,输出结果为:

Calling expensive_computation with arguments (3,) and {}
expensive_computation returned 9
9
Calling expensive_computation with arguments (3,) and {}
expensive_computation returned 9
9

解释

  1. 日志记录装饰器:记录函数的调用,包括输入参数和返回值。
  2. 权限检查装饰器:检查用户是否具有调用函数的权限。
  3. 缓存装饰器:缓存函数的返回结果,以提高性能。

通过这种方式,我们可以在不修改函数本身的情况下,为函数添加额外的功能。

5. 总结

装饰器是 Python 中一个非常强大的工具,可以用来扩展和修改函数或方法的行为。通过装饰器,我们可以在不修改原始代码的情况下为函数添加额外的功能。在实际开发中,装饰器有很多应用场景,包括日志记录、访问控制、性能优化等。希望本文能够帮助你更好地理解和使用 Python 中的装饰器。


欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力