当发电机超出范围时,清理它

时间:2017-05-16 01:30:39

标签: python python-3.x garbage-collection generator

我有一个必须执行清理步骤的生成器,即使它从未迭代过:

def gen(data):
    while True:
        item = data.get()
        if item is None:
            break
        # ...
        try:
            yield transformed_item
        except GeneratorExit:
            break
    # clean up; must happen if gen was called
    # ...

当我这样称呼它时,一切正常(即清理发生):

for x in gen(data):
    # ...

或者像这样:

g = gen(data)
r = next(g)
# ...

但是当生成器超出范围而没有任何人在其上调用next时,当然它根本不执行任何代码,因此GeneratorExit不会在其中引发,并且清理没有发生:

g = gen(data)
# g was never used before going out of scope
del g

如果生成器在有机会产生任何东西之前超出范围,我怎样才能重构代码以保证清理步骤的发生?

1 个答案:

答案 0 :(得分:1)

您可以使用上下文处理程序。这取决于你需要多长时间来保持发电机。

class Gen(object):

    def __init__(self, data):
        self.data = data

    def __enter__(self):
        return self._gen(self.data)

    def __exit__(self, exc_type, exc_val, exc_tb):
        # Cleanup
        print 'Cleaning up'

    def _gen(self, data):
        for i in data:
            yield i

然后它看起来像:

with Gen(data) as g:
    r = next(g)

编辑:

鉴于您无法强制最终用户使用上下文管理器的限制,您是否可以将生成器创建包装在另一个函数中并“生成”生成器?

def gen(data):
    g = _gen(data)
    next(g)
    return g


def _gen(data):
    yield None
    while True:
        ... # Rest of generator