为什么发电机不是上下文管理器

时间:2014-06-03 17:41:44

标签: python generator contextmanager

发电机可以管理资源,例如来自上下文管理器内部的yield。 一旦调用生成器的close()方法(或引发异常),就会释放资源。

由于最后很容易忘记调用close(),我认为使用上下文管理器也是显而易见的(并且还要处理潜在的异常)。 我知道我可以使用contextlib.closing,但在with语句中直接使用生成器会不会更好?

生成器是否为上下文管理器是否有原因?

2 个答案:

答案 0 :(得分:4)

一般而言,您没有看到更多生成器作为上下文管理器而反之亦然的原因是它们旨在解决不同的问题。上下文管理器的出现是因为它提供了一种简洁的方法,可以将可执行代码放到资源中。

您可能希望将实现__iter__()的类与上下文管理器(单一责任原则)分开,这是一个很好的理由。单一责任归结为概念

  

让一个班做一件事,做得好

列表是可迭代的,但那是因为它们是一个集合。除了他们持有的东西之外,他们不管理任何状态,迭代只是访问该状态的另一种方式。除非你需要迭代作为访问包含对象的状态的手段,否则我看不出将两者混合在一起的理由。即便如此,我仍会竭尽全力以真正的OO风格将其分开。

答案 1 :(得分:1)

像Wheaties说的那样,你希望课程只做“一件事,做得好”。特别是对于上下文管理器,他们正在管理上下文。那么问问自己,这里的背景是什么?大多数时候,它将开放资源。前一段时间我问过using a queue with a context manager,响应基本上是一个队列作为一个上下文没有意义。但是,“在一个任务中”是我所处的真实背景,为此制作一个上下文管理器是有意义的。

此外,没有迭代的with语句。例如,我无法打开一个文件并在一个语句中迭代它:

for line in file with open(filename) as file:
    ...

必须分两行完成:

with open(filename) as file:
    for line in file:
        ...

这很好,因为被管理的上下文不是“我们正在遍历文件”,而是“我们打开了一个文件”。那么,背景是什么?你到底在做什么?很可能,你的托管上下文实际上并不是通过资源的迭代。但是,如果您查看特定问题,您可能会发现确实存在生成器正在管理上下文的情况。希望了解上下文的真实情况应该为您提供有关如何正确管理它的一些想法。