欢迎访问宙启技术站
智能推送

函数的装饰器:如何扩展和修改已有函数

发布时间:2023-06-25 13:14:25

函数的装饰器是Python中一种重要的编程技巧,可以实现在不修改已有函数源码的情况下,对函数的功能进行扩展和修改。本文将从以下几个方面介绍函数的装饰器:装饰器的定义和使用、常见的装饰器实现方式以及实际应用案例。

一、装饰器的定义和使用

装饰器本质上是一个可以接受一个函数作为参数,并返回一个新函数的函数。装饰器可以用来给函数增加新的功能,比如:计时器、缓存、参数验证等。

通过使用@符号和装饰器函数名称,可以让装饰器对目标函数进行装饰,示例如下:

def my_decorator(func):  # 定义一个装饰器函数
    def wrapper():  # 定义一个包装函数
        print("Before function is called.")
        func()
        print("After function is called.")
    return wrapper  # 返回包装函数

@my_decorator  # 使用@符号和装饰器函数名称,将函数进行装饰
def say_hello():
    print("Hello!")

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

执行结果:

Before function is called.
Hello!
After function is called.

在上面的示例中,@my_decorator语句将装饰器应用于say_hello函数。当调用say_hello函数时,其实是调用了装饰器中的wrapper函数,wrapper函数在调用原始函数say_hello之前和之后添加了额外的功能。

二、常见的装饰器实现方式

常见的装饰器实现方式有:函数嵌套、函数装饰器类、类装饰器等。

1. 函数嵌套

函数嵌套是最常见的装饰器实现方式,它是利用内函数的概念,在调用被装饰函数前后添加一些额外的功能。示例代码如下:

def time_it(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("耗时:{}".format(end_time - start_time))
        return result
    return wrapper

@time_it
def my_function(input):
    time.sleep(1)
    return input

print(my_function("Hello, World!"))

在上面的示例中,time_it是一个装饰器函数,my_function是一个被装饰的函数。该装饰器使用time库计算函数的执行时间。

2. 函数装饰器类

函数装饰器类相比函数嵌套更加灵活,可以通过实例变量存储数据,并支持初始化和销毁方法。

示例代码如下:

class MyDecorator:
    def __init__(self, func):
        self.func = func
        self.counter = 0

    def __call__(self, *args, **kwargs):
        self.counter += 1
        result = self.func(*args, **kwargs)
        print("调用次数:{}".format(self.counter))
        return result

@MyDecorator
def my_function(input):
    return input

print(my_function("Hello"))
print(my_function("World"))

在上面的示例中,MyDecorator是一个装饰器类,它维护了一个计数器变量。每次调用被装饰的函数,计数器就会加一。

3. 类装饰器

类装饰器指的是一个类对象可以作为装饰器来使用。类装饰器可以用于修改函数的参数、增加函数的属性等。

示例代码如下:

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

    def __call__(self, *args, **kwargs):
        result = self.func(*args, **kwargs)
        return "Decorator: " + result

@MyDecorator
def my_function(input):
    return input

print(my_function("Hello, World!"))

在上面的示例中,MyDecorator是一个类装饰器,它在函数调用后返回一个新的字符串。

三、实际应用案例

1. 缓存装饰器

缓存装饰器可以将函数的计算结果缓存起来,在下次调用时直接返回缓存结果。这样可以减少函数重复计算。示例代码如下:

def memoize(func):
    cache = {}

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

    return wrapper

@memoize
def fibonacci(n):
    if n in (0, 1):
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))

在上面的示例中,memoize是一个缓存装饰器,它使用一个字典存储缓存结果。当函数被调用时,装饰器首先判断缓存中是否有结果,有则直接返回,否则计算结果并将其存储在缓存中。

2. 参数检查装饰器

参数检查装饰器可以用来检查函数参数的有效性。如果参数无效,则抛出异常。示例代码如下:

def validate_args(*validators):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for validator in validators:
                if not validator(*args, **kwargs):
                    raise ValueError(f"Invalid arguments: {args}, {kwargs}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@validate_args(lambda x: isinstance(x, int),
               lambda x: isinstance(x, int),
               lambda x: x != 0)
def divide(a, b):
    return a / b

print(divide(10, 2))
print(divide("hello", 2))
print(divide(10, 0))

在上面的示例中,validate_args是一个参数检查装饰器,它接受一个或多个参数检查函数作为输入。当函数被调用时,装饰器会检查其参数是否满足所有的参数检查函数。如果参数无效,则抛出异常。

四、总结

本文介绍了函数的装饰器的定义和使用,常见的装饰器实现方式以及实际应用案例。通过使用装饰器,我们可以很方便地扩展和修改已有的函数,从而使代码更加灵活、可维护。