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

Python 函数的装饰器用法

发布时间:2023-06-16 13:08:44

Python 中的函数装饰器是一个经典的特性,它可以让我们在不修改原有函数代码的情况下,添加额外的功能和逻辑。虽然在使用 Python 时,我们可能已经使用了各种装饰器,但是如果我们想系统地了解 Python 函数装饰器,那么就需要更深入地理解它的定义、语法、应用场景等方面。

1. 装饰器的定义

函数装饰器是一个高阶函数,它接受一个函数,并以某种方式返回一个新函数。这个新函数通常会在原函数的基础上添加一些额外的功能,有时还会修改原函数的参数和返回值。

需要注意的是,装饰器并不会修改原函数本身的代码,而是通过类似“包裹”原函数的方式实现增加功能。这种方式称为“封装”,即在函数的前后添加一些额外的代码,实现某种功能(如日志记录、异常处理、缓存等)。

2. 装饰器的语法

Python 函数装饰器的语法非常简单,其基本格式如下:

def decorator(func):
    def wrapper(*args, **kwargs):
        # 添加装饰器的逻辑
        return func(*args, **kwargs)
    return wrapper

这个函数用于定义一个装饰器,其中包含一个内部函数 wrapper,用于添加装饰器的逻辑,并在最后返回这个新函数。这个装饰器可以被其他函数调用,在这一过程中,原有的函数就被“包裹”在这个装饰器内部函数中,以实现某种特殊功能。

3. 装饰器的应用场景

Python 函数装饰器的应用场景非常广泛。它可以用于实现函数输出日志,缓存经常使用的计算结果,设置函数超时时间等。

以下是一些比较常见的应用场景:

1)记录函数运行时间:

import time

def run_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__}运行时间: {end_time - start_time}")
        return result
    return wrapper

@run_time
def test():
    time.sleep(3)

test()

2)对函数进行缓存:

CACHE = {}

def cache(func):
    def wrapper(*args, **kwargs):
        key = str(args) + str(kwargs)
        if key in CACHE:
            return CACHE[key]
        result = func(*args, **kwargs)
        CACHE[key] = result
        return result
    return wrapper

@cache
def calculate(a, b):
    return a + b

result = calculate(1, 2)
result = calculate(1, 2) # 第二次调用时已经从缓存中返回结果,不需要再重新计算

3)设置函数超时时间:

import signal

class TimeoutError(Exception):
    pass

def timeout(seconds):
    def inner(func):
        def wrapper(*args, **kwargs):
            def signal_handler(signum, frame):
                raise TimeoutError("Function call timed out")
            signal.signal(signal.SIGALRM, signal_handler)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
                signal.alarm(0) # 在函数调用后清除定时器
                return result
            except:
                signal.alarm(0) # 在异常时清除定时器
                raise TimeoutError("Function call timed out")
        return wrapper
    return inner

@timeout(2)
def test():
    time.sleep(3)

try:
    test()
except TimeoutError:
    print("Function call timed out")

4. 装饰器的注意事项

虽然 Python 函数装饰器很方便,但是有几个注意事项需要我们注意:

1)装饰器不能应用于类方法和静态方法

2)装饰器应该被放在函数调用前面

3)多个装饰器,从上到下依次执行

4)装饰器会包装原有函数,因此有可能改变原有函数的属性(如函数名和文档字符串)。

5. 总结

Python 函数装饰器是一种高级技术,它可以在不修改原函数代码的情况下,实现对函数功能的增强。装饰器的定义、语法、应用场景等都非常重要,因此我们需要熟练掌握它们,才能更好地利用 Python 装饰器来提高工作效率。