前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python专家编程系列: 3. 善用装饰器使代码提高一个层次(Powerful Python Decorator)

Python专家编程系列: 3. 善用装饰器使代码提高一个层次(Powerful Python Decorator)

原创
作者头像
AIFEx
发布2023-10-06 11:25:02
3180
发布2023-10-06 11:25:02
举报
文章被收录于专栏:AIFEx的专栏AIFEx的专栏

0. 标题

Python专家编程系列: 3. 善用装饰器使代码提高一个层次(Powerful Python Decorator)

代码语言:txt
复制
作者: quantgalaxy@outlook.com   
blog: https://blog.csdn.net/quant_galaxy  
欢迎交流

1. 常用的装饰器

1.1 cache

请注意,它仅适用于 Python >= 3.9。

这样就可以缓存以前的值并重复使用,而不是重新计算。

代码语言:python
复制
from functools import cache

@cache
def factorial(n):
    return n * factorial(n-1) if n else 1

print(factorial(10))

Output:

代码语言:shell
复制
3628800

这个装饰器,把factorial的每个步骤的值都记录下来了,在递归的过程中,就可以重复使用,并且在下次访问中也可以重复使用。

1.2 lru_cache

和cache类似,不过有一个maxsize参数,用来设置缓存的最大数量,避免内存膨胀。

当缓存已满并且需要存储新结果时,最近最少使用的结果将从缓存中逐出以为新结果腾出空间。这称为最近最少使用 (LRU) 策略。

默认情况下,maxsize 设置为 128。如果将其设置为 None,如我们的示例,LRU 功能将被禁用,并且缓存可以无限增长。

代码语言:python
复制
from functools import lru_cache
import time


@lru_cache(maxsize=None)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)


start_time = time.perf_counter()
print(fibonacci(30))
end_time = time.perf_counter()
print(f"The execution time: {end_time - start_time:.8f} seconds")
# The execution time: 0.000023434 seconds

1.3 wraps

@wraps修饰器用于在修饰函数或方法后保留其元数据。

这对于调试、内省和文档目的非常有用。

比如下面这个,加入调试信息的使用:

代码语言:python
复制
from functools import wraps

def debug(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args={args} kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper


@debug
def my_function(x, y):
    return x + y

my_function(1, 2) # prints "Calling my_function with args=(1, 2) kwargs={}" and "my_function returned 3"

下面这个例子展示了使用这个装饰器后,原函数的内置变量都被保留了下来:

代码语言:python
复制
from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # do something before
        result = func(*args, **kwargs)
        # do something after
        return result
    return wrapper


@my_decorator
def my_function():
    """My function docstring"""
    pass


print(my_function.__name__) # my_function
print(my_function.__doc__) # My function docstring
代码语言:txt
复制
作者: quantgalaxy@outlook.com   
blog: https://blog.csdn.net/quant_galaxy  
欢迎交流

1.4 timeit

@timeit装饰器用于测量函数的执行时间并将其打印到控制台。

这对于分析代码和查找性能瓶颈非常有用。

代码语言:python
复制
import time
from functools import wraps

def timeit(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f'{func.__name__} took {end - start:.6f} seconds to complete')
        return result
    return wrapper


@timeit
def process_data():
    time.sleep(1)

process_data()
# process_data took 1.000012 seconds to complete

1.5 contextmanager

@contextmanager装饰器用于定义一个函数,该函数可用作带有 with 语句的上下文管理器。

这对于自动获取和释放资源(如文件句柄或锁)非常有用。

代码语言:python
复制
from contextlib import contextmanager

@contextmanager
def my_context_manager():
    # acquire resource
    yield
    # release resource

with my_context_manager():
    # use resource
    pass

1.6 atexit.register

atexit 模块的 @register 装饰器可以让我们在 Python 解释器退出时执行一个函数。

这个装饰器对于执行最终任务非常有用,例如释放资源或只是打印调试信息:

代码语言:python
复制
import atexit

@atexit.register
def goodbye():
    print("Bye bye!")

print("Hello Tim!")

Output:

代码语言:shell
复制
Hello Tim!
Bye bye!

2. 作者信息

代码语言:txt
复制
作者: quantgalaxy@outlook.com   
blog: https://blog.csdn.net/quant_galaxy  
欢迎交流

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. 标题
  • 1. 常用的装饰器
    • 1.1 cache
      • 1.2 lru_cache
        • 1.3 wraps
          • 1.4 timeit
            • 1.5 contextmanager
              • 1.6 atexit.register
              • 2. 作者信息
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档