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

函数装饰器

发布时间:2023-05-31 12:29:46

函数装饰器是 Python 中一种让程序员不必修改已有函数结构就能为其添加特殊功能的语法。它可以在运行时动态地修改函数的参数、调用方式、返回值等等,从而简化代码、提高效率和可读性。

使用函数装饰器有很多好处。首先,它能够让你避免重复代码,因为你只需要定义一次装饰器函数,就可以在多个函数中使用它。其次,它能够让你在不修改原函数的情况下添加新的功能,比如缓存、性能统计、日志记录等等。最后,它能够提高代码可读性,因为使用装饰器可以让你把各种相关的逻辑分离开,使代码更加模块化和易于维护。

下面我们来看一个例子,说明如何使用函数装饰器来实现一个简单的日志记录功能:

def log(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数 {func.__name__},参数为 {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 返回 {result}")
        return result
    return wrapper

@log
def add(x, y):
    return x + y

print(add(1, 2))

在这个例子中,我们定义了一个名为 log 的装饰器函数。这个函数接受一个函数作为参数,并返回一个新的函数 wrapper,这个函数就是装饰器函数的核心逻辑。在 wrapper 函数中,我们首先输出了被装饰函数的名字和参数,然后调用原函数,并将原函数的返回值存储在 result 变量中。最后,再输出被装饰函数的名字和返回值,并将 result 返回。

在获得了 log 装饰器函数之后,我们可以使用 @log 语法来装饰另一个函数。在这个例子中,我们把装饰器函数应用到了一个名为 add 的函数上。这样一来,每次调用 add 函数的时候,都会先输出类似 "调用函数 add,参数为 (1, 2), {}" 这样的信息,然后再输出函数的返回值。

除了上面这个例子外,还有很多其他的例子可以帮助你更好地理解函数装饰器的用法。下面我们来看一些常见的案例。

缓存

使用函数装饰器可以很方便地实现缓存功能。假设我们有一个网络服务,需要从另外一个服务上获取一些数据,但是这个服务的响应比较慢。为了减少网络开销,我们可以在本地缓存这些数据,然后再使用缓存数据来响应客户端请求。

下面是一个示例代码:

import time

def cache(func):
    cache = {}
    def wrapper(*args):
        if args in cache:
            print('命中缓存:', args)
            return cache[args]
        else:
            result = func(*args)
            cache[args] = result
            print('未命中缓存:', args)
            return result
    return wrapper

@cache
def slow(x):
    time.sleep(2)
    return f"{x} 的平方是 {x * x}"

print(slow(10))
print(slow(10))

在这个例子中,我们定义了一个名为 cache 的装饰器函数。这个函数用一个字典来表示缓存,每当有人调用被装饰的函数时,都会检查这个字典中是否已经存有要求的结果,如果已经有了,就直接返回;否则,就调用原函数并把结果存入缓存中。

我们在 slow 这个函数上应用了 cache 这个装饰器函数。这个函数很慢,它需要花费两秒钟来计算结果。但是,因为我们使用了装饰器,所以第二次调用 slow 函数就不会再花费两秒钟来计算结果,而是直接从缓存中读取结果并返回。

比较器

使用函数装饰器可以很方便地实现比较器功能。假设我们有一些数据需要排序,但是它们的类型各不相同。在这种情况下,我们就需要能够比较任意两个对象,然后按照它们的大小关系进行排序。比较函数通常是比较麻烦的,因为我们需要定义一个函数来实现每一个对象类型之间的比较。但是,使用函数装饰器,我们可以轻松地扩展比较器功能。

下面是一个示例代码:

def compare(cmp_func):
    def wrapped_cmp(x, y):
        if isinstance(x, str) and isinstance(y, str):
            return cmp_func(x.lower(), y.lower())
        else:
            return cmp_func(x, y)
    return wrapped_cmp

@compare
def my_max(x, y):
    return x if x > y else y

print(my_max('abc', 'def'))
print(my_max(1, 2))

在这个例子中,我们定义了一个名为 compare 的装饰器函数。这个函数接受一个比较函数作为参数,然后返回一个新的比较函数 wrapped_cmp。在 wrapped_cmp 函数中,我们检查被比较的两个对象是否都是字符串,如果是,就先转化为小写字母,然后再调用比较函数。否则,就直接调用比较函数。这个 wrapped_cmp 函数就是我们扩展后的比较器。在函数定义后,我们用 @compare 语法来应用 compare 装饰器。

在这个例子中,我们使用了一个简单的比较函数 my_max 来测试 compare 装饰器。这个函数接受两个参数,返回较大的那个。在使用装饰器后,我们就可以用 my_max 来比较任意两个对象了。