【问题标题】:How do I prevent my list comprehension from raising a stopIteration error如何防止我的列表理解引发 stopIteration 错误
【发布时间】:2017-06-17 06:17:47
【问题描述】:

我正在逐步浏览一个包含 3 行长记录的文本文件。如果在第一行中,我可以说“这是一条我不想计算的记录”,我想移动到下一条记录的开头,再往下 2 行。目前,我正在运行这样的代码 sn-p:

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]

衷心感谢大家的帮助。

【问题讨论】:

  • 假设当你点击下一个时还剩下 1 或 0 个项目。这应该创建长度为 1 或 0 的列表,还是应该是某种错误?
  • 好问题!这应该打破记录处理,开始处理不同的文件。有没有一种方法可以让我在推进列表之前知道列表中还有多少元素?

标签: python for-loop list-comprehension stopiteration


【解决方案1】:

您可以使用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))

【讨论】:

  • 嘿,这太棒了!我要试一试,看看它是如何工作的!谢谢!
  • 名单!这就是我所缺少的——我在 some_list 上尝试了 len、str 和 int,并且就像“我必须真正花一些时间在这个上!”最终,我最终使用正则表达式替换来删除非标准长度,然后再进行修改。谢谢你们!
【解决方案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)

【讨论】:

  • 哦,我也喜欢这个!这个概念我很熟悉,所以我认为在未来的迭代中,我会使用这个实现。谢谢!
猜你喜欢
  • 2018-10-08
  • 2010-09-05
  • 2017-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多