在使用map停止迭代之前引发的ValueError(下一个,iterables)

2024-09-28 23:31:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在写一个循环,在4个列表迭代器上如下所示:

it0 = iter(['foo','bar'])
it1 = iter(['bar','foo'])
it2 = iter(['foo','foo'])
it3 = iter(['bar','bar'])

try:
    a, b, c, d = map(next, (it0, it1, it2, it3))
    while True:
        #some operations that can raise ValueError
        if a+b+c+d == 'foobar'*2:
            a, b, c, d = map(next, (it0, it1, it2, it3))
        elif a+b == 'foobar':
            c, d = map(next,(it2, it3))
        else:
            a, b = map(next,(it0, it1))
except StopIteration:
    pass

但是当我在Python3中运行这段代码时,我得到一个ValueError: not enough values to unpack (expected 2, got 0)在预期的StopIteration之前出现。在

我不想在except语句中捕捉ValueError,因为while循环中的某些操作也可能导致ValueError,该操作应停止程序。在

next怎么不在赋值之前引发它的异常?在

在Python2.7中,StopIteration首先被引发。在


Tags: map列表foobarnextfoobarvalueerrorexcept
2条回答

引发了StopIteration,但元组赋值将其吞并,因为它将StopIteration视为来自map()迭代器的信号,该迭代器生成值:

>>> i0, i1 = iter(['foo']), iter([])
>>> m = map(next, (i0, i1))
>>> next(m)
'foo'
>>> next(m)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> i0, i1 = iter(['foo']), iter([])
>>> m = map(next, (i0, i1))
>>> a, b = m
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 2, got 1)

这是正常的行为;期望迭代器作为输入的Python内置程序总是使用StopIteration作为“迭代完成”信号,元组解包必须在这里迭代。在

请先将map()输出转换为列表并测试长度,对每个iterable分别使用next(),而不是使用map(),或者在本地捕获{}。在

测试长度必须重新提高StopIteration

^{pr2}$

注意,这里list()吞并了StopIteration异常。在

仅为map()操作捕获ValueError

try:    
    a, b, c, d = map(next, (it0, it1, it2, it3))
except ValueError:
    raise StopIteration

在每个迭代器上单独调用next(),根本不使用map()

a, b, c, d = next(it0), next(it1), next(it2), next(it3)

或者使用列表理解:

a, b, c, d = [next(i) for i in (it0, it1, it2, it3)]

这两种方法都确保在赋值发生之前调用next(),而不是在赋值过程中调用。在

根据Martijn Pieters的回答,直接使用列表理解是有效的:

a, b, c, d = [next(it) for it in (it0, it1, it2, it3)]

post澄清了为什么for在iterable上而不是在循环体中捕捉{}。在

另一种可能的方法是,利用nextdefault参数:

^{pr2}$

相关问题 更多 >