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

Python装饰器:如何扩展和修改函数的功能

发布时间:2023-12-04 00:31:47

Python装饰器是一种用于扩展和修改函数功能的语法。它可以在不修改原始函数代码的情况下,通过包装函数的方式,在函数执行前后添加额外的功能。这种方式可以提供很大的灵活性,使我们能够轻松地修改和更新已有的函数,同时也使代码更具可读性和可维护性。

装饰器的实现方式非常简单,它本质上是一个函数,它接收一个函数作为输入,并返回一个新的函数作为输出。在返回的新函数中,我们可以添加任意额外的处理逻辑,包括修改函数输入、输出,添加日志、计时等功能。

下面是一个示例,其中定义了一个装饰器函数log_time,它接收一个函数作为输入,并返回一个新的函数。在返回的新函数中,我们首先打印当前时间,然后调用传入的函数,最后再次打印当前时间。这样就实现了一个简单的计时功能。

import time

def log_time(func):
    def wrapper(*args, **kwargs):
        print("Current time:", time.time())
        result = func(*args, **kwargs)
        print("Current time:", time.time())
        return result
    return wrapper

@log_time
def my_function():
    time.sleep(1)
    print("Function executed")

my_function()

输出结果为:

Current time: 1638530781.2071207
Function executed
Current time: 1638530782.2102845

可以看到,装饰器log_time在函数my_function执行前后分别打印了当前时间,并计算了函数执行的时间消耗。

在实际应用中,装饰器经常用于添加日志、缓存、鉴权、限流等功能。下面我们来看一个实际的示例,使用装饰器实现一个简单的缓存功能。

def cache(func):
    cache_dict = {}
    
    def wrapper(*args, **kwargs):
        key = str(args) + str(kwargs)
        if key in cache_dict:
            print("Get result from cache")
            return cache_dict[key]
        
        result = func(*args, **kwargs)
        cache_dict[key] = result
        return result
    
    return wrapper

@cache
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

print(factorial(5))
print(factorial(5))

输出结果为:

120
Get result from cache
120

可以看到,装饰器cache在计算阶乘的过程中,将每次计算的结果缓存起来。当下次需要计算同样的阶乘时,直接从缓存中获取结果,减少了计算的时间消耗。

除了使用@符号来应用装饰器外,我们还可以手动将装饰器应用到函数上。例如,下面的代码等价于上述示例:

def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

factorial = cache(factorial)

print(factorial(5))
print(factorial(5))

在实际开发中,我们也可以使用多个装饰器嵌套来实现更复杂的功能扩展。装饰器的执行顺序与装饰器的位置相关,离函数定义越近的装饰器将越早执行。

def decorator1(func):
    print("Decorator 1")
    return func

def decorator2(func):
    print("Decorator 2")
    return func

@decorator1
@decorator2
def my_function():
    print("Function executed")

my_function()

输出结果为:

Decorator 2
Decorator 1
Function executed

最后需要注意的一点是,装饰器会改变函数的属性,例如__name____doc__。为了避免这种情况,我们可以使用functools模块中的wraps装饰器来修复这些属性。

总的来说,装饰器是一种强大的工具,它能够扩展和修改函数的功能,提供更高级的编程方式。熟练掌握装饰器的使用,将有助于提升代码的可读性和可维护性,同时也使我们能够更加灵活地修改和更新函数的逻辑。