2

我想逐行解析一个字符串,并为每个解析的结果提供一个生成器。迭代这些结果的代码如果找到它想要的信息,它可能会选择不迭代整个序列:

import StringIO

def foo(string):
  sstream = StringIO.StringIO(string)
  for line in sstream:
    res = doSomethingWith(line)
    yield res
  sstream.close()

for bar in foo(mystring):
  if condition(bar):
     break

我想,如果变成,这将保持sstream打开状态。保证在我们完成迭代后将关闭的最佳方法是什么?我是否必须将生成器包装在类定义中并实现?或者我可以在这里依靠垃圾收集吗?我计划调用很多不同的字符串。condition(bar)Truesstreamfoo()__del__foo()

4

2 回答 2

2

保证sstream在我们完成迭代后将关闭的最佳方法是foo()什么?

在绝对必须调用的“清理”函数的一般情况下,您可能必须在生成器之外调用它,例如......

from StringIO import StringIO

def foo(sstream):
    for line in sstream:
        res = doSomethingWith(line)
        yield res

sio = StringIO(mystring)
try:
    for bar in foo(sio):
        if condition(bar):
            break
finally:
    sio.close()

上下文管理器似乎不能在生成器内部工作,除非它们已经筋疲力尽。例如...

from StringIO import StringIO
from contextlib import contextmanager

@contextmanager
def my_stringio(s):
    print 'creating StringIO'
    sio = StringIO(s)
    yield sio
    print 'calling close()'
    sio.close()

def mygen():
    with my_stringio('abcdefghij') as sio:
        while 1:
            char = sio.read(1)
            if not char:
                break
            yield char

for char in mygen():
    print char
    if char == 'c':
        break

...从不打印'calling close()'

我是否必须将生成器包装在类定义中并实现 __del__

这是另一种选择,但这种方法的问题在于,如果您设法用类实例创建循环引用,则该__del__方法将永远不会被调用。

或者我可以在这里依靠垃圾收集吗?

在这种情况下,您可以。

使用 a调用该方法StringIO并不重要。close()您可能要确保的唯一一件事是它正在使用的内存已被垃圾收集,无论您的for循环终止的方式如何,这都会发生 - 生成器将超出范围,并且其本地将被 GC'd。

于 2013-06-18T09:43:59.197 回答
1

编辑:不要介意下面的废话;据我所知,您需要在 yield 所在的 for 循环中执行中断。

可能这样的工作?我很容易忽略一些东西。

import StringIO

# perform the break on the inner forloop first, to ensure sstream gets closed
break_ = false
def foo(string, break_):
  sstream = StringIO.StringIO(string)
  for line in sstream:
    res = doSomethingWith(line)
    if not break_: yield res
    else: break
  sstream.close()

for bar in foo(mystring, break_):
  if break_:
      break
  elif condition(bar):
     break_ = True
于 2013-06-18T08:36:39.140 回答