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

Python的装饰器函数:用法和实例

发布时间:2023-06-06 15:57:31

Python的装饰器是一种在不修改它本身的情况下增加其功能的函数或类。在一个函数或类的定义之前使用@符号和装饰器函数名称,可以将其装饰上其他功能。Python的装饰器可以帮助我们在不改变原有代码的基础上实现横向扩展,提高代码的可重用性和可维护性。

下面我们来具体介绍一下Python的装饰器函数的用法和实例。

1. 带参数的装饰器

在Python中,装饰器函数可以带参数。例如,可以定义一个带参数的装饰器函数,实现多个装饰器的功能,例如对函数运行时间进行统计、打印函数错误信息等。

下面是一个例子:

import time

def time_count(logger):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            logger("the function %s run for %d seconds" % (func.__name__, (end_time - start_time)))
            return result
        return wrapper
    return decorator

@time_count(logger=print)
def test_func():
    time.sleep(1)

test_func()

在这个例子中,我们定义了一个函数time_count,它接受一个参数logger,logger是一个函数,用来打印日志。它返回一个decorator函数,用来装饰需要进行时间统计的函数。

decorator函数中定义一个wrapper函数,wrapper函数可以接受任意数量任意类型的位置参数和关键字参数。wrapper函数会先记录当前时间,再调用原函数(即需要进行时间统计的函数),记录函数运行时间,最后调用logger函数,输出函数运行时间。wrapper函数返回原函数的运行结果。

在test_func函数上使用带参数的装饰器time_count,可以接收参数logger,打印函数运行时间。

2. 修饰类方法的装饰器

Python中的功能强大的类装饰器,可以为一个类添加新的方法或修改原有方法的功能。下面是一个例子,我们定义一个修饰类方法的装饰器,为类方法添加一个prefix参数:

def add_prefix(prefix):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            return prefix + func(self, *args, **kwargs)
        return wrapper
    return decorator

class MyClass:
    def __init__(self, value):
        self.value = value

    @add_prefix(prefix='Hello, ')
    def my_method(self):
        return str(self.value)

instance = MyClass(value='world')
print(instance.my_method())

在这个例子中,我们定义了一个装饰器函数add_prefix,它接受参数prefix,返回一个decorator函数。decorator函数会包装原有的类方法,通过在方法前面添加prefix来扩展实例的方法。

MyClass的实例instance在调用my_method方法时,会先调用add_prefix方法包装my_method方法,返回一个修改过的new_method方法,再调用new_method方法,实现在my_method方法前加上'Hello, '的效果。

3. 嵌套装饰器的用法

Python中的装饰器可以嵌套使用。下面是一个例子,我们定义了一个嵌套装饰器的函数,来实现对序列类型数据进行缓存的装饰器:

from functools import wraps

def cache_decorator(func):
    cache = {}

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

    return wrapper

def list_cache_decorator(func):
    @cache_decorator
    def wrapper(*args):
        if isinstance(args[0], list):
            args = tuple(args[0])
        return func(*args)

    return wrapper

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

print(factorial([5]))

在这个例子中,我们定义了两个装饰器函数:cache_decorator和list_cache_decorator。其中list_cache_decorator是一个嵌套装饰器,调用了cache_decorator函数来实现对序列类型数据进行缓存。

cache_decorator函数使用了一个字典对象cache,用来缓存原函数factorial的运行结果。如果原函数已经被调用过,且参数相同,直接返回缓存结果即可。如果缓存区没有结果,则调用原有的函数,并将结果更新到缓存区。

list_cache_decorator函数调用了cache_decorator函数,并使用了Python中内置的functools.wraps函数来将包装的函数wrapper的属性还原为原函数factorial的属性,这样就可以在包装函数wrapper中通过isinstance函数来判断参数是否是序列类型,并将序列类型的参数转化为tuple类型的参数,以便放入缓存区。最后返回了包装的函数wrapper。

在Python中,装饰器的用法非常灵活,它不仅可以增加函数的功能、调整函数的参数、还可以增加类的功能,使得代码实现起来更加简单和优雅。 在日常开发中,我们可以根据业务需求,结合装饰器的特性,实现不同的功能模块。