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

Python函数进阶技巧:使用装饰器在函数执行前后添加额外逻辑

发布时间:2023-05-31 04:14:58

装饰器是 Python 中常用的一种高阶函数,可以在不改变原代码的情况下给函数增加功能。装饰器通常用于在函数执行前后添加额外的逻辑,比如记录日志、验证参数、缓存结果等。

在介绍装饰器之前,先了解一下 Python 中的函数对象。在 Python 中,函数也是一种对象,可以当做参数传入函数,也可以当做函数的返回值返回。这就是 Python 中的“一切皆对象”的思想。因为函数是一种对象,所以我们可以对其进行操作,比如:

def hello():
    print('hello')
    
# 给函数对象添加属性
hello.name = 'hello'
print(hello.name)   # 输出 'hello'

当然,这种操作并不常见。常见的操作是将函数作为参数传入另一个函数中,并在这个函数中对其进行修改、扩展等操作。这就是装饰器的基本思想。

下面我们来对一个函数进行装饰器的操作。我们假设有一个函数 print_time,用于输出当前时间。现在我们想要在这个函数的执行前后分别输出一些信息,可以通过装饰器实现:

import time

def before_after(func):
    def wrapper():
        print('before')
        func()
        print('after')
    return wrapper

@before_after
def print_time():
    print(time.strftime('%Y-%m-%d %H:%M:%S'))

print_time()

上述代码定义了一个名为 before_after 的函数,用于接收另一个函数作为参数,并返回一个函数对象。我们将另一个函数 print_time 传入 before_after 中,并在前后分别输出信息。实现过程中,我们定义了一个名为 wrapper 的函数,它使用了闭包的方式来保存传入的函数对象,以便后续调用。在最后,我们使用 @before_after 的语法糖来装饰 print_time 函数。

输出结果如下:

before
2021-11-08 09:53:45
after

可以看到,执行 print_time 函数时,before_after 装饰器添加了额外的逻辑,输出了 before 和 after。这是一种非常常见的装饰器用法,比如在函数执行前后记录一些信息、计算函数执行时间等。下面我们再给出几个常见的装饰器示例。

### 1. 计算函数执行时间

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__} executed in {end_time-start_time}s')
        return result
    return wrapper

@timer
def expensive_calculation(n):
    return sum(range(n))

expensive_calculation(1000000)

上述代码定义了一个名为 timer 的装饰器,用于计算函数的执行时间。在 wrapper 函数中,我们记录函数执行前后的时间,并输出执行时间。在最后,我们使用 @timer 的语法糖来装饰 expensive_calculation 函数。

输出结果如下:

expensive_calculation executed in 0.027530908584594727s

可以看到,执行 expensive_calculation 函数时,timer 装饰器添加了额外的逻辑,计算了函数执行时间,并输出了执行时间。

### 2. 缓存函数结果

def cache(func):
    cache = {}
    
    def wrapper(*args, **kwargs):
        key = args + tuple(sorted(kwargs.items()))
        if key in cache:
            print(f'cache hit: {key}')
            return cache[key]
        else:
            result = func(*args, **kwargs)
            cache[key] = result
            return result
        
    return wrapper

@cache
def slow_function(n):
    time.sleep(1)
    return n ** 2

slow_function(3)
slow_function(3)

上述代码定义了一个名为 cache 的装饰器,用于缓存函数的执行结果。在 wrapper 函数中,我们先检查函数的参数是否已经在缓存中,如果存在则直接返回结果,否则执行函数并将结果保存在缓存中。在最后,我们使用 @cache 的语法糖来装饰 slow_function 函数。

输出结果如下:

3
cache hit: (3,)

可以看到, 次执行 slow_function 函数时,经过了 1s 的计算,输出了计算结果 9。第二次执行时,cache 装饰器缓存了计算过程,并输出了 cache hit: (3,),表示直接从缓存中取出了结果。

装饰器是 Python 中非常强大的一种编程技巧,可以用于实现很多有用的功能。除了上述示例中的计算执行时间、缓存结果等功能外,还可以用装饰器来实现日志记录、性能统计、权限检查、错误处理等功能。在实际工作中,我们可以根据需求编写自己的装饰器,提高代码的可重用性和可维护性。