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

Python装饰器函数:如何使用装饰器改进函数

发布时间:2023-06-11 18:27:31

Python 装饰器是一种特殊的函数,它可以修改其他函数的行为。使用装饰器可以改进函数,同时也能够使代码更加具有可读性。

在 Python 中,函数和类都是对象,都可以作为参数传递给其他函数。因此,Python 装饰器就是一个接受函数对象作为参数的函数,返回一个新的函数对象。

以下是一个简单的装饰器示例:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

def say_hello():
    print("Hello!")

say_hello = my_decorator(say_hello)

say_hello()

运行上述代码会输出:

Before the function is called.
Hello!
After the function is called.

在上面的例子中,my_decorator 是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数。wrapper 函数是一个内部函数,它包装了 say_hello 函数,添加了一些额外的逻辑。最后,函数对象 say_hello 被重新赋值,它指向了新的函数对象 wrapper

在 Python 中,有一种更方便的方式来应用装饰器,即使用 @ 符号。以下是上面的示例代码使用 @ 符号的写法:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

这种写法可以更加方便地应用装饰器,不需要手动重新赋值函数对象。

接下来,我们会介绍如何使用装饰器来改进函数的行为。

### 给函数添加计时功能

有些时候,我们需要统计一个函数的运行时间。使用装饰器,我们可以方便地给函数添加计时功能。以下是一个计时装饰器的示例代码:

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__} elapsed time: {(end_time - start_time):.4f} seconds")
        return result
    return wrapper

在上面的代码中,我们定义了一个计时装饰器 timer。它接受一个函数作为参数,使用 time 模块来计算函数的运行时间,并输出运行时间。最后,它返回原来的函数。

接下来,我们可以使用 @timer 装饰器来装饰需要计时的函数。以下是一个示例代码:

@timer
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

result = fib(30)
print(result)

在上面的代码中,我们使用 @timer 装饰器来装饰 fib 函数,它会计算 fib(30) 函数的运行时间,并输出结果。这个示例稍微有些耗时,大概需要等待一段时间才能得到计时结果。

### 给函数添加缓存功能

有些时候,我们会需要缓存函数的结果,以便在需要时快速获取到结果。使用装饰器,我们可以方便地实现缓存功能。以下是一个缓存装饰器的示例代码:

def cache(func):
    cache_dict = {}
    def wrapper(*args):
        if args in cache_dict:
            print("From cache")
            return cache_dict[args]
        else:
            result = func(*args)
            cache_dict[args] = result
            print("New calculation")
            return result
    return wrapper

在上面的代码中,我们定义了一个缓存装饰器 cache。它使用一个字典来保存函数输入和输出之间的映射关系。当函数被调用时,如果输入已经在缓存中,就直接返回缓存结果;否则计算新结果,并将结果保存到缓存中。

接下来,我们可以使用 @cache 装饰器来装饰需要缓存的函数。以下是一个示例代码:

@cache
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

result = fib(30)
print(result)

在上面的代码中,我们使用 @cache 装饰器来装饰 fib 函数,它会缓存 fib(30) 函数的结果,并输出结果。由于斐波那契数列的递归计算非常耗时,使用缓存装饰器可以大大提高计算效率。

### 给函数添加日志功能

有些时候,我们需要记录函数的输入和输出,以便后续调试和分析。使用装饰器,我们可以方便地添加日志功能。以下是一个日志装饰器的示例代码:

def log(func):
    def wrapper(*args, **kwargs):
        args_str = ", ".join(repr(arg) for arg in args)
        kwargs_str = ", ".join(f"{key}={repr(value)}" for key, value in kwargs.items())
        signature = f"{func.__name__}({args_str}, {kwargs_str})"
        result = func(*args, **kwargs)
        print(f"{signature} -> {result}")
        return result
    return wrapper

在上面的代码中,我们定义了一个日志装饰器 log。它使用字符串拼接的方式记录函数的输入和输出,并输出日志信息。

接下来,我们可以使用 @log 装饰器来装饰需要记录日志的函数。以下是一个示例代码:

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

result = add(2, 3)
print(result)

在上面的代码中,我们使用 @log 装饰器来装饰 add 函数,它会记录 add(2, 3) 函数的输入和输出,并输出日志信息。

### 小结

Python 装饰器是一种非常有用的语言特性,它可以用来修改其他函数的行为,同时也能够使代码更加具有可读性。使用装饰器,我们可以方便地给函数添加计时、缓存、日志等功能,从而使代码更加模块化和可维护。