这是forPython中的循环:
for_stmt ::= "for" target_list "in" expression_list ":" suite
Run Code Online (Sandbox Code Playgroud)
通常,当从中产生值时expression_list会引发异常,循环将中止.是否有一种优雅的方式(没有重写循环使用while True或类似的东西)来捕获此异常并继续循环?
这是一个例子:
import csv
csv.field_size_limit(10)
reader = csv.reader(open('test.csv', 'r'))
for line in reader:
print(line)
Run Code Online (Sandbox Code Playgroud)
用这个文件:
foo,bar,baz
xxx,veryverylong,yyy
abc,def,ghi
Run Code Online (Sandbox Code Playgroud)
这在第二行中止.我想要一种方法来跳过或记录失败的行并继续.
aba*_*ert 30
如果你的内部迭代可以在异常之后继续,那么你需要包装它是一个简单的生成器:
def wrapper(gen):
while True:
try:
yield next(gen)
except StopIteration:
raise
except Exception as e:
print(e) # or whatever kind of logging you want
pass
Run Code Online (Sandbox Code Playgroud)
例如:
In [9]: list(wrapper(csv.reader(open('test.csv', 'r'))))
field larger than field limit (10)
Out[9]: [['foo', 'bar', 'baz'], ['abc', 'def', 'ghi']]
Run Code Online (Sandbox Code Playgroud)
另一方面,如果异常后内部迭代器无法继续,则无法将其包装起来:
def raisinggenfunc():
yield 1
raise ValueError("spurious error")
yield 3
In [11]: list(wrapper(raisinggenfunc()))
spurious error
Out[11]: [1]
Run Code Online (Sandbox Code Playgroud)
通过调用Python生成器函数或评估生成器表达式创建的任何生成器都不可恢复.
在这种情况下,您需要找到一些方法来创建一个恢复迭代的新迭代器.对于类似的东西csv.reader,这意味着n在将文件包装成文件之前从文件中读取行csv.reader.在其他情况下,它可能意味着传递n给构造函数.在其他情况下 - raisinggenfunc如上所述,这是不可能的.
您可以将阅读器包装在另一个迭代器中,然后根据需要处理异常。
class ExceptionHandlingIterator(object):
def __init__(self, iterable):
self._iter = iter(iterable)
self.handlers = []
def __iter__(self):
return self
def next(self):
try:
return self._iter.next()
except StopIteration as e:
raise e
except Exception as e:
for handler in self.handlers:
handler(e)
return self.next()
csv_reader = ExceptionHandlingIterator(csv.reader(open('test.csv', 'r'))
# attach handlers to the reader here
for line in csv_reader:
print line
Run Code Online (Sandbox Code Playgroud)