我想逐行解析一个字符串,并为每个解析的结果提供一个生成器。迭代这些结果的代码可以选择不迭代整个序列,如果它找到了它想要的信息:
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)
,这将使True
保持打开状态。当我们完成对sstream
的迭代时,保证foo()
将被关闭的最佳方法是什么?我是否必须将生成器包装在类定义中并实现__del__
?或者我可以依赖垃圾收集吗?我打算给foo()
打电话以获取很多不同的字符串。
答案 0 :(得分: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__
方法将永远不会被调用。
或者我可以依靠垃圾收集吗?
在这种情况下,你可以。
使用StringIO
,如果调用close()
方法,则无关紧要。您可能想要确保的唯一事情是它正在使用的内存已被垃圾收集,无论您的for
循环终止的方式如何都会发生 - 生成器将超出范围,其本地将是GC'd。
答案 1 :(得分:1)
这样的工作可能吗?我很容易忽略一些事情。
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