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

Python装饰器:如何使用装饰器实现函数扩展?

发布时间:2023-06-24 18:36:40

Python装饰器是一种可以在不修改原函数代码的前提下对函数功能进行扩展的技术。其本质是一个函数,接受被装饰的函数作为参数,返回一个内部函数,该内部函数包含对原函数的扩展操作。本文将介绍如何使用Python装饰器实现函数扩展。

1、装饰器的基本语法

Python中的装饰器可以使用@符号来定义,其基本语法如下:

@decorator

def func(parameters):

function_body

decorator是一个装饰器函数,用来扩展func函数的功能。在函数调用时,Python解释器会将@decorator下面的函数作为参数传递给decorator函数,并将其返回的函数对象赋值给func函数名。

2、装饰器的应用实例

下面的代码展示了一个简单的装饰器实例,用于统计函数执行时间。

import time

def time_it(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print('函数%s执行时间:%.2f秒' % (func.__name__, end - start))
        return result
    return wrapper

@time_it
def my_func(a, b):
    time.sleep(1)
    return a + b

print(my_func(1, 2))

在上面的例子中,time_it是一个装饰器函数,用于记录函数的执行时间。被装饰的函数my_func接收两个参数a和b,其中包含一个停顿1秒钟的操作,然后将a和b相加的结果返回。

在my_func函数定义的下一行,使用了@time_it语法糖,表示将time_it函数作为装饰器函数应用到my_func函数上面。当执行my_func函数时,会先执行time_it函数,并将my_func函数作为参数传递给它。time_it函数返回一个包含扩展操作的函数wrapper,最终将其赋值给了my_func函数名。也就是说,当我们调用my_func函数时,实际上调用的是被扩展后的wrapper函数。

运行上面的代码,我们可以看到my_func函数执行花费了1.00秒的时间,确切的时间会因计算机性能而有所不同。

3、装饰器的多重应用

装饰器函数可以多次应用于同一个函数,从而实现更为复杂的扩展操作。例如下面的代码中,time_it和log_it两个装饰器将同时应用于my_func函数。

import time

def time_it(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print('函数%s执行时间:%.2f秒' % (func.__name__, end - start))
        return result
    return wrapper

def log_it(func):
    def wrapper(*args, **kwargs):
        print('开始执行函数%s' % func.__name__)
        result = func(*args, **kwargs)
        print('函数%s执行完成' % func.__name__)
        return result
    return wrapper

@log_it
@time_it
def my_func(a, b):
    time.sleep(1)
    return a + b

print(my_func(1, 2))

在上面的例子中,我们先使用time_it装饰器对my_func函数进行扩展,对其执行时间进行记录。然后使用log_it装饰器再次对my_func函数进行扩展,增加了日志打印功能。两个装饰器的顺序非常重要,@log_it应该在@time_it之前,因为它们的执行顺序是从下往上的。运行上面的代码,我们可以看到my_func函数在执行完毕之后,会输出执行日志和执行时间,验证了这种嵌套装饰器的使用方式。

4、带参数的装饰器

装饰器不仅可以对函数进行扩展,还可以接受参数,在不同的参数下实现不同的扩展操作。例如下面的代码中,定义了一个limit_time装饰器,可以控制函数执行的最大时间。当函数的执行时间超过了限制时间,将返回特定的错误信息。

import time

def limit_time(seconds):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            if end - start > seconds:
                print('函数%s执行超时,最大时间为%.2f秒' % (func.__name__, seconds))
                return None
            return result
        return wrapper
    return decorator

@limit_time(2)
def my_func(a, b):
    time.sleep(3)
    return a + b

print(my_func(1, 2))

在上面的例子中,我们定义了一个limit_time函数,它接受一个参数seconds,用于控制函数的最大执行时间。在其内部定义了一个decorator函数,接受一个func参数,它定义了一个wrapper函数,用于实现对func函数的扩展操作。当执行时间超过规定的时间时,wrapper函数将返回None值,表示函数执行失败。最后,limit_time函数返回decorator函数,用于应用到my_func函数上面。

在下面的代码中,my_func函数被装饰器装饰后,它的最大执行时间被设为2秒。然而,我们在函数体内进行了3秒的停留,因此它的执行时间将超时,返回值为None,表示执行失败。这验证了limit_time装饰器的使用效果。

5、类装饰器的使用

装饰器不仅可以是函数,还可以是类。类装饰器是面向对象编程的一项技术,其本质是定义了一个类,其中包含__init__和__call__两个特殊方法。__init__方法用于初始化实例对象,__call__方法用于实现对象调用时的操作。下面的代码展示了一个用于计算函数调用次数的类装饰器。

class Counter:
    def __init__(self, func):
        self.func = func
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print('函数%s调用次数:%d' % (self.func.__name__, self.count))
        return self.func(*args, **kwargs)

@Counter
def my_func(a, b):
    return a + b

print(my_func(1, 2))
print(my_func(2, 3))
print(my_func(3, 4))

在上面的例子中,我们使用类定义了一个装饰器Counter,该装饰器统计了函数调用的次数,并输出调用次数信息。在__init__方法中,我们初始化了一个计数器变量count,并将被装饰的函数func保存在成员变量中。在__call__方法中,每次函数调用时我们都会将计数器加1,并输出调用次数信息;然后调用被装饰的函数并将其返回。

在下面的代码中,我们使用类装饰器Counter装饰了my_func函数,并在其每次调用时输出调用次数。我们依次调用my_func函数三次,其输出信息应该依次为“函数my_func调用次数:1”,“函数my_func调用次数:2”和“函数my_func调用次数:3”。

6、总结

本文介绍了Python装饰器的基本语法、应用实例、多重应用、带参数的装饰器、类装饰器等几个方面。Python装饰器是一种非常实用的技术,它可以在不修改