详解Python 装饰器

  • Post category:Python

Python装饰器可以动态地修改一个函数的行为,常常由于一些公共的功能需要所有函数都具有时才会使用。本文将详细讲解Python装饰器的使用方法。

什么是装饰器

装饰器其实是一个Python函数,它接收另一个函数作为参数,并且返回一个新的函数。这个新函数的特点是在不改变原函数的情况下,添加一些新的功能,然后返回一个修改后的函数。

基本的装饰器

假设我们有一个say_hello函数,它返回一个greeting字符串。

def say_hello():
    return "Hello"

现在我们想要在这个函数之前打印一条消息,也就是添加一个新的功能,我们可以使用一个装饰器来实现。

def print_message(func):
    def wrapper():
        print("Before the function is called.")
        func()

    return wrapper

@print_message
def say_hello():
    return "Hello"

say_hello()

运行这段代码,我们会发现输出了:

Before the function is called.

然后输出:

Hello

现在,我们已经使用一个简单的装饰器添加了新的功能。

带参数的装饰器

装饰器的语法允许我们在调用函数时传递参数。例如,我们想要让我们的装饰器接受一个字符串参数,并将它打印出来。

def print_message(message):
    def decorator(func):
        def wrapper():
            print(message)
            func()

        return wrapper

    return decorator

@print_message("Before the function is called.")
def say_hello():
    print("Hello")

say_hello()

运行这段代码,我们会发现它会打印:

Before the function is called.
Hello

这里我们将装饰器分为两个函数,第一个print_message的参数是需要传递给装饰器的字符串,它返回一个第二个函数decorator,应用装饰器的函数将传递给这个函数,这个函数返回一个新的函数wrapper,新函数里面拥有之前的函数原有的行为,并且还会在打印我们传递的字符串之后再执行它。

这里的decorator函数是一个工厂函数,它返回一个真正的装饰器函数,这个函数才是真正的装饰器。

示例1:计时器

我们可以使用装饰器来记录函数执行的时间。以下是一个计时器装饰器的例子:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} took {end_time - start_time} seconds.")
        return result

    return wrapper

@timer
def slow_function():
    time.sleep(2)

@timer
def fast_function():
    time.sleep(0.5)

slow_function()
fast_function()

这段代码中,我们定义了一个计时器装饰器timer,它接收一个函数作为参数,并返回一个新函数wrapper。在新函数里面,我们记录了函数开始执行时的时间start_time,调用原始函数,并记录函数结束执行的时间end_time。最后我们计算出函数执行的时间,并输出结果。

在我们的例子中,我们定义了两个函数分别是slow_functionfast_function,并分别使用了装饰器来计算它们的执行时间。我们通过调用time.sleep函数模拟了不同的函数执行时间。执行这段代码后,我们会看到输出内容类似于:

Function slow_function took 2.0016019344329834 seconds.
Function fast_function took 0.502479076385498 seconds.

这个装饰器可以让我们在调试和优化代码时很方便地了解函数运行的时间。

示例2:日志记录

当我们构建一个程序并自己维护时,我们需要记录各种信息以方便自己的调试。在这种情况下,装饰器能够帮助我们记录程序的运行时状态。

def logger(func):
    def wrapper(*args, **kwargs):
        print(f"INFO: Running {func.__name__}")
        result = func(*args, **kwargs)
        print(f"INFO: Finished {func.__name__}")
        return result

    return wrapper

@logger
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")

这段代码中,我们定义了一个装饰器logger,它接收一个函数作为参数,并返回一个新函数wrapper。在新函数里面,我们打印日志信息,调用原始函数,并在函数执行完毕后再次输出日志。

在我们的例子中,我们定义了一个函数say_hello并使用了装饰器logger。当我们调用这个函数时,它将打印出一条信息表示这个函数正在运行,然后输出”Hello, “并跟着一个姓名。最后,它会再次输出一条信息表示这个函数已经完成。执行这段代码后,我们会看到输出内容类似于:

INFO: Running say_hello
Hello, Alice!
INFO: Finished say_hello

这个装饰器可以帮助我们在调试时更好地了解函数的运行情况。

以上是Python装饰器的一个基本攻略,认真理解和掌握装饰器的使用,可以让我们更好的利用Python的函数,进而提高我的编程能力。