page contents

Python装饰器:实现代码精简的利器!

本文讲述了python装饰器:实现代码精简的利器!具有很好的参考价值,希望对大家有所帮助。一起跟随好学星城小编过来看看吧,具体如下:

attachments-2024-03-0xwmSW726607a85331d74.png本文讲述了python装饰器:实现代码精简的利器!具有很好的参考价值,希望对大家有所帮助。一起跟随好学星城小编过来看看吧,具体如下:

今天,我们来探索 Python 装饰器的强大功能,学习如何通过使用装饰器来减少代码量,提高效率与可读性。

什么是装饰器

装饰器(decorator)是 Python 中一种强大的特性,它允许你改变函数或类的行为,而无需修改其源代码。装饰器本质上是一个函数,它接收另一个函数作为参数,并返回一个新的函数,这个新函数会包裹原始函数。通过这种方式,你可以在不修改原始函数的情况下,为其添加一些额外的功能或逻辑。

例如,假设你有一个函数,用于在控制台打印一条消息:

def hello():

    print("Hello, world!")

现在,假设你想测量这个函数的执行时间。你可能会这样做:

import time

def hello():

    start = time.time()    

    print("Hello, world!")   

    end = time.time()

    print(f"执行时间: {end - start} 秒")

但考虑到测量执行时间的功能很可能会复用,我们最好将它独立封装成一个函数,使用 time 模块来计算执行时间,然后调用原始函数:

import time

def measure_time(func):

    def wrapper():

        start = time.time()

        func()

        end = time.time()

        print(f"执行时间: {end - start} 秒")

    return wrapper

注意,measure_time 函数返回了另一个名为wrapper的函数,这是原始函数的修改版本。wrapper 函数做了两件事:它记录了执行的开始和结束时间,并调用了原始函数。

现在,要使用这个函数,只需要:

hello = measure_time(hello)

hello()

这将输出类似于这样的内容:

Hello, world!

执行时间: 0.000123456789 秒

通过这种方式,你无需修改hello函数的代码,就为其添加了测量执行时间的新功能。然而,有一种更优雅和简洁的方法来实现这一点,那就是使用装饰器。装饰器是一种语法糖,允许你使用@符号将一个函数应用到另一个函数上。例如,我们可以像这样重写前面的代码:

@measure_time

def hello():

    print("Hello, world!")

hello()

这将产生与之前相同的输出,但代码量大大减少。@measure_time这一行等同于hello = measure_time(hello),但它看起来更清晰,更易于阅读。

为什么要用装饰器

使用装饰器的原因有很多,例如:

代码可复用。例如,如果你有许多需要测量执行时间的函数,你可以简单地为它们都应用相同的装饰器,而不是一遍又一遍地编写相同的代码。

遵循单一职责的原则。例如,如果你有一个执行复杂计算功能的函数,你可以使用装饰器来处理日志记录、错误处理、缓存或验证输入和输出,而不必弄乱函数的主要逻辑。

扩展功能的同时无需修改源代码。例如,如果你正在使用一个第三方库的类或函数,但你想为它们添加一些额外的功能或行为,你可以使用装饰器来包装它们,并根据你的需要进行定制。

装饰器示例

Python 中有许多内置装饰器,如@staticmethod、@classmethod、@property、@functools.lru_cache、@functools.singledispatch等。你也可以创建自己的自定义装饰器来满足各种需求。以下是一些可以有效精简代码的自定义装饰器示例:

@timer装饰器

这个装饰器与我们上面看到的@measure_time装饰器类似,但可以应用于任意数量参数的函数。它还使用functools.wraps装饰器来保留原始函数的名称和文档字符串(docstring)。代码如下:

import time

from functools import wraps

def timer(func):

    @wraps(func)

    def wrapper(*args, **kwargs):

        start = time.time()

        result = func(*args, **kwargs)

        end = time.time()

        print(f"{func.__name__}的执行时间: {end - start} 秒")

        return result

    return wrapper

现在,你可以使用这个装饰器来测量任何函数的执行时间,例如:

@timer

def factorial(n):

    """返回n的阶乘"""

    if n == 0 or n == 1:

        return 1

    else:

        return n * factorial(n - 1)

@timer

def fibonacci(n):

    """返回第n个斐波那契数"""

    if n == 0 or n == 1:

        return n

    else:

        return fibonacci(n - 1) + fibonacci(n - 2)

print(factorial(10))

print(fibonacci(10))

这将输出类似于这样的内容:

factorial的执行时间: 1.1920928955078125e-06 秒

3628800

fibonacci的执行时间: 0.000123456789 秒

55

通过这种方式,@timer装饰器为factorial和fibonacci函数添加了测量执行时间的新功能。

@debug装饰器

这个装饰器可用于调试目的,它支持输出它所装饰的函数的名称、参数和返回值。并使用functools.wraps装饰器来保留原始函数的名称和文档字符串。代码如下:

from functools import 

def debug(func):

    @wraps(func)

    def wrapper(*args, **kwargs):

        print(f"调用 {func.__name__},参数: {args},关键字参数: {kwargs}")

        result = func(*args, **kwargs)

        print(f"{func.__name__} 返回: {result}")

        return result

    return wrapper

现在,你可以使用这个装饰器来调试任何函数,例如:

@debug

def add(x, y):

    """返回x和y的和"""

    return x + y

@debug

def greet(name, message="Hello"):

    """返回带有名字的问候语"""

    return f"{message}, {name}!"

print(add(2, 3))

print(greet("Alice"))

print(greet("Bob", message="Hi"))

这将输出类似于这样的内容:

调用 add,参数: (2, 3),关键字参数: {}

add 返回: 5

5

调用 greet,参数: ('Alice',),关键字参数: {}

greet 返回: Hello, Alice!

Hello, Alice!

调用 greet,参数: ('Bob',),关键字参数: {'message': 'Hi'}

greet 返回: Hi, Bob!

Hi, Bob!

通过这种方式,@debug装饰器为add和greet函数添加了调试功能,能够清晰地显示函数调用时的参数和返回值。

@memoize装饰器

这个装饰器对于优化函数性能非常有用(尤其是用了递归、或是需要大量计算的函数),因为它缓存了之前调用的结果,并在再次传递相同的参数时返回这些结果。同样使用了functools.wraps装饰器来保留原始函数的名称和文档字符串。代码如下:

from functools import wraps

def memoize(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

现在,你可以使用这个装饰器来缓存任何函数的结果,例如:

@memoize

def factorial(n):

    """返回n的阶乘"""

    if n == 0 or n == 1:

        return 1

    else:

        return n * factorial(n - 1)

@memoize

def fibonacci(n):

    """返回第n个斐波那契数"""

    if n == 0 or n == 1:

        return n

    else:

        return fibonacci(n - 1) + fibonacci(n - 2)

print(factorial(10))

print(fibonacci(10))

这将输出与之前相同的结果,但执行时间会快得多,因为执行结果做了缓存。

通过这种方式,@memoize装饰器为factorial和fibonacci函数添加了缓存结果的功能,大大提高了这些函数的执行效率。

结语

Python 装饰器是一种强大而优雅的特性,能够在不修改源代码的前提下,改变函数或类的行为。它们可以帮助你减少代码量,提高代码的可读性,复用性,降低耦合性,以及扩展现有代码的功能。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2024-03-30 13:51
  • 阅读 ( 62 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
小柒
小柒

1470 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1470 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章