1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
    3. # 你想自己去实现一个新的上下文管理器,以便使用with语句。
    4. # 实现一个新的上下文管理器的最简单的方法就是使用 contexlib 模块中的 @contextmanager 装饰器。 下面是一个实现了代码块计时功能的上下文管理器例子:
    5. import time
    6. from contextlib import contextmanager
    7. @contextmanager
    8. def timethis(label):
    9. start = time.time()
    10. try:
    11. yield
    12. finally:
    13. end = time.time()
    14. print('{}: {}'.format(label, end - start))
    15. with timethis('counting'):
    16. n = 10000000
    17. while n > 0:
    18. n -= 1
    19. # counting: 1.2312605381011963
    20. # 在函数 timethis() 中,yield 之前的代码会在上下文管理器中作为 __enter__() 方法执行, 所有在 yield 之后的代码会作为 __exit__() 方法执行。 如果出现了异常,异常会在yield语句那里抛出。
    21. # 下面是一个更加高级一点的上下文管理器,实现了列表对象上的某种事务:
    22. @contextmanager
    23. def list_transaction(orig_list):
    24. working = list(orig_list)
    25. yield working
    26. orig_list[:] = working
    27. items = [1, 2, 3]
    28. with list_transaction(items) as working:
    29. working.append(4)
    30. working.append(5)
    31. print(items) # [1, 2, 3, 4, 5]
    32. with list_transaction(items) as working:
    33. working.append(6)
    34. working.append(7)
    35. raise RuntimeError('oops')
    36. # items
    37. # [1, 2, 3, 4, 5]
    1. # 通常情况下,如果要写一个上下文管理器,你需要定义一个类,里面包含一个 __enter__() 和一个 __exit__() 方法,如下所示:
    2. import time
    3. class timethis:
    4. def __init__(self, label):
    5. self.label = label
    6. def __enter__(self):
    7. self.start = time.time()
    8. def __exit__(self, exc_type, exc_val, exc_tb):
    9. end = time.time()
    10. print('{}: {}'.format(self.label, end - self.start))
    11. with timethis('耗时') as t:
    12. n = 10000000
    13. while n > 0:
    14. n -= 1
    15. # 耗时: 1.266099452972412
    16. # @contextmanager 应该仅仅用来写自包含的上下文管理函数。 如果你有一些对象(比如一个文件、网络连接或锁),需要支持 with 语句,那么你就需要单独实现 __enter__() 方法和 __exit__() 方法。