假设我们有这个递归函数(生成器)
data = [1,[21, 22, [231, 232, 233]], [31, 32, 33]]
def listgen(data):
for each in data:
if type(each) is int:
yield str(each)
elif type(each) is list:
g = listgen(each)
for i in g:
yield i
else:
continue
gen = listgen(data)
print ' '.join(gen)
输出是:
1 21 22 231 232 233 31 32 33
现在...我如何将其编写为类,因为我需要为该生成器定义 .close() 方法?
最佳答案
当您在生成器上调用 close
时,它会在当前暂停执行的位置引发 GeneratorExit
。您可以捕获该异常,并在重新引发异常之前在 except
block 中进行清理(不允许忽略它)。
对于递归生成器来说,这有点复杂,因为您需要手动将异常传播到递归堆栈。但即便如此也不是太难。这是生成器的一个版本,当关闭时,它会在其执行的每个级别上打印“清理”。如果在从示例数据集中生成 231 后立即关闭它,您将得到 3 次,列表中的每一层嵌套一次。在您的实际用例中,您可以将其替换为代码来关闭数据库连接,或者执行您必须执行的任何其他清理工作。
def closable_listgen(data):
try:
for each in data:
if type(each) is int:
yield str(each)
elif type(each) is list:
g = closable_listgen(each)
try:
for i in g:
yield i
except GeneratorExit:
g.close()
raise
else:
continue
except GeneratorExit:
print("cleaning up")
raise
Python 3.3 使这变得更简单,因为新的 yield from
语法会自动为我们传播对 close
生成器链的调用:
def closable_listgen33(data):
try:
for each in data:
if type(each) is int:
yield str(each)
elif type(each) is list:
g = closable_listgen33(each)
yield from g
else:
continue
except GeneratorExit:
print("cleaning up")
raise
为了更好地衡量,以下是如何将生成器实现为一个类(这是您最初要求的):
class list_gen_class(object):
def __init__(self, data):
self.iterator = iter(data)
self.child = None
def __iter__(self):
return self
def __next__(self):
while True:
if self.child:
try:
return next(self.child)
except StopIteration:
self.child = None
value = next(self.iterator)
if isinstance(value, int):
return str(value)
elif isinstance(value, list):
self.child = list_gen_class(value)
def close(self):
if self.child:
self.child.close()
print("cleaning up")
关于python - 生成器类的实例(递归),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13512007/