更多课程 选择中心


Python培训

400-996-5531

深入解析 Python 中的上下文管理器


通常我们希望把一些操作放到一个代码块中,在代码块中执行时就可以保持在某种运行状态,而当离开该代码块时就执行另一个操作,结束当前状态;所以,简单来说,上下文管理器的目的就是规定对象的使用范围,如果超出范围就采取“处理”。Python提供了不同的方法来管理执行时间。例如,您可以使用Python的内置timeit模块来管理一小段代码的执行时间。

>>> import timeit

>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)

0.3018611848820001

但是,timeit.timeit函数仅接受字符串,如果要管理比较复杂的函数时会有局限性。以下示例向您展示如何使用timeit模块运行和管理函数。

def test()

: """Stupid test function"""

L = [i for i in range(100)]

if __name__ == '__main__':

import timeit

print(timeit.timeit("test()", setup="from __main__ import test"))

尽管它可以工作,但看起来并不是真正的pythonic。管理执行时间的另一种方法是利用Python的内置cProfile模块,但是并不建议用它,实际上它不是很精确,这只是一种变通方法,可让您了解某些代码段需要执行多长时间。您可以通过以下方式使用它:

>>> python -m cProfile <file_name.py>

既然上面的两种方法都不是非常Pythonic并且都有缺陷,那么我们如何实现一个比较完美的解决方案呢?

其实很简单:我们只要能拿到程序开始执行和结束执行的时间就可以了,下面介绍具体方法,Python有一个内置模块可供我们使用:time。

>>> import time

>>> start = time.time()

>>> # do some stuff

>>> end = time.time()

>>> print(f"Elapsed Time: {end - start}")

但是这样写不是很方便。我们可以创建一个上下文管理器。

创建一个上下文管理器

使用Python创建上下文管理器有两种不同方法,我们将研究两种方法来实现此目的:基于类和基于生成器的上下文管理器。

基于类的上下文管理器

要创建基于类的上下文管理器,需要先实现魔法变量__enter__和__exit__。进入上下文(或代码块)时调用第一个,离开上下文时调用后者。

有了这些准备,我们就可以来创建一个实现这两种方法的Timer类。进入代码块时,我们希望获取当前时间并将其保存到表示开始的变量中。如果我们离开代码块,我们想获取当前时间并从中减去开始时间。结果被打印出来。

为了自定义输出,我们让用户指定一个语句,该语句在经过的时间之前打印。以下要点向您展示了一个即用型的类。

from time import time

class Timer(object):

def __init__(self, description):

self.description = description

def __enter__(self):

self.start = time()

def __exit__(self, type, value, traceback):

self.end = time()

print(f"{self.description}: {self.end - self.start}")

with Timer("List Comprehension Example"):

s = [x for x in range(10_000_000)]

基于生成器的上下文管理器

基于生成器的方法更加简单。我们可以创建一个包含程序流程的生成器函数(获取开始和结束时间以及打印经过的时间)。@contextmanager装饰器通过使用GeneratorContextManager对象包装生成器,将生成器功能转换为适当的上下文管理器。

from contextlib import contextmanager

from time import time

@contextmanager

def timing(description: str) -> None:

start = time()

yield

ellapsed_time = time() - start

print(f"{description}: {ellapsed_time}")

with timing("List Comprehension Example"):

s = [x for x in range(10_000_000)]

如果执行了with后面的代码块,将跳回到yield关键字之后的位置继续执行。

总结

在本文中,我们学习了如何创建自己的时间上下文管理器。了解基本概念,我们可以通过两种方式实现上下文管理器:基于类和基于生成器。生成的类和生成器函数可以直接使用。

预约申请免费试听课

填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:Python|如何构建自己的IP池
下一篇:六个Python经典面试题(附详解)

2021年Python全套免费视频教程在哪里?

Python编程学习路线

Python最高有几级?

人工智能与语音遥控的区别?

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省