如何防止我的列表理解引发 stopIteration 错误
How do I prevent my list comprehension from raising a stopIteration error
我正在逐步浏览一个包含 3 行记录的文本文件。如果在第一行,我可以说 "this is a record that I don't want to count",我想移动到下一条记录的开头,再往下 2 行。目前,我 运行 是这样的代码片段:
lines = content.split("\n")
iterable = iter(xrange(len(lines)))
for i in iterable:
line = lines[i]
...
if isRecord(keyword) == False:
[iterable.next() for x in range(2)]
在文件的最后,我的理解有可能会引发 stopIteration 错误。我如何添加到我的代码中,以便在我引发 stopIteration 时它会中断 for 循环?我看过许多关于列表理解的条目,以及如何构建 for 循环以根据 stopIteration 标志停止,但我还不明白如何将其应用到我自己的代码中。我还看到了具有 if/else/for 风格的列表推导式,但我可以构建一个具有如下风格的列表推导式吗:
[iterable.next() for x in range(2) else break]
衷心感谢大家的帮助。
您可以使用 itertools
切片。 some_list
的长度为 2、1 或 0,具体取决于列表的剩余部分。如果列表较大,将从迭代器中删除 2 个项目,for 循环将继续下一个项目。
import itertools
lines = content.split("\n")
iterable = iter(xrange(len(lines)))
for i in iterable:
line = lines[i]
...
if isRecord(keyword) == False:
some_list = list(itertools.islice(iterable, 2))
你也可以用这样的方式构建你的迭代器,你可以同时获得 3 个项目,例如使用来自 itertools 模块的 recipe
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
例如
>>> for x in grouper(xrange(10),3):
print x
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
(9, None, None)
>>>
所以对于你的情况你可以这样做
lines = content.split("\n")
for line,x,y in grouper(lines,3):
...
if not isRecord(keyword) :
continue # go to the next iteration
或者如果内容不是纯 3 行块的格式,则消费配方
from itertools import islice
import collections
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
例子
>>> it=iter(xrange(10))
>>> consume(it,5)
>>> list(it)
[5, 6, 7, 8, 9]
>>>
你也可以使用 enumerate
来了解你是否真的需要它,例如
lines = content.split("\n")
iterator = iter(enumerate(lines))
for i,line in iterator:
...
if not isRecord(keyword) :
consume(iterator,2)
我正在逐步浏览一个包含 3 行记录的文本文件。如果在第一行,我可以说 "this is a record that I don't want to count",我想移动到下一条记录的开头,再往下 2 行。目前,我 运行 是这样的代码片段:
lines = content.split("\n")
iterable = iter(xrange(len(lines)))
for i in iterable:
line = lines[i]
...
if isRecord(keyword) == False:
[iterable.next() for x in range(2)]
在文件的最后,我的理解有可能会引发 stopIteration 错误。我如何添加到我的代码中,以便在我引发 stopIteration 时它会中断 for 循环?我看过许多关于列表理解的条目,以及如何构建 for 循环以根据 stopIteration 标志停止,但我还不明白如何将其应用到我自己的代码中。我还看到了具有 if/else/for 风格的列表推导式,但我可以构建一个具有如下风格的列表推导式吗:
[iterable.next() for x in range(2) else break]
衷心感谢大家的帮助。
您可以使用 itertools
切片。 some_list
的长度为 2、1 或 0,具体取决于列表的剩余部分。如果列表较大,将从迭代器中删除 2 个项目,for 循环将继续下一个项目。
import itertools
lines = content.split("\n")
iterable = iter(xrange(len(lines)))
for i in iterable:
line = lines[i]
...
if isRecord(keyword) == False:
some_list = list(itertools.islice(iterable, 2))
你也可以用这样的方式构建你的迭代器,你可以同时获得 3 个项目,例如使用来自 itertools 模块的 recipe
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
例如
>>> for x in grouper(xrange(10),3):
print x
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
(9, None, None)
>>>
所以对于你的情况你可以这样做
lines = content.split("\n")
for line,x,y in grouper(lines,3):
...
if not isRecord(keyword) :
continue # go to the next iteration
或者如果内容不是纯 3 行块的格式,则消费配方
from itertools import islice
import collections
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
例子
>>> it=iter(xrange(10))
>>> consume(it,5)
>>> list(it)
[5, 6, 7, 8, 9]
>>>
你也可以使用 enumerate
来了解你是否真的需要它,例如
lines = content.split("\n")
iterator = iter(enumerate(lines))
for i,line in iterator:
...
if not isRecord(keyword) :
consume(iterator,2)