为什么“map”隐藏“StopIteration”?

rod*_*on7 7 python python-3.x

map()我发现了一种使用不等同于列表理解的情况。next当用作第一个参数时会发生这种情况。

例如:

l1 = [1, 2]
l2 = ['hello', 'world']
iterators = [iter(l1), iter(l2)]

# list comprehension
values1 = [next(it) for it in iterators]
# values1 = [1, "hello"]
values2 = [next(it) for it in iterators]
# values2 = [2, "world"]
values3 = [next(it) for it in iterators]
# raise StopIteration
Run Code Online (Sandbox Code Playgroud)
l1 = [1, 2]
l2 = ['hello', 'world']
iterators = [iter(l1), iter(l2)]

# map
values1 = list(map(next, iterators))
# values1 = [1, "hello"]
values2 = list(map(next, iterators))
# values2 = [2, "world"]
values3 = list(map(next, iterators))
# values3 = []
# doesn't raise StopIteration
Run Code Online (Sandbox Code Playgroud)

任何其他异常都会按其应有的方式发生。例子:

def divide_by_zero(value: int):
    return value // 0

l = [1, 2, 3]
values = list(map(divide_by_zero, l))
# raises ZeroDivisionError as expected
values = [divide_by_zero(value) for value in l]
# raises ZeroDivisionError as expected, too
Run Code Online (Sandbox Code Playgroud)

看起来很奇怪。它与 Python 3.9 和 Python 3.11 的工作方式相同。

看起来像map()这样工作:

def map(func, iterator):
    try:
        while True:
            item = next(iterator)
            yield func(item)
    except StopIteration:
        pass
Run Code Online (Sandbox Code Playgroud)

但我希望它能像这样工作:

def map(func, iterator):
    while True:
        try:
            item = next(iterator)
        except StopIteration:
            break
        yield func(item)
Run Code Online (Sandbox Code Playgroud)

这是一个错误吗?

che*_*ner 6

尝试next致电map

>>> >>> m = map(next, iterators)
>>> next(m)
1
>>> next(m)
'hello'
>>> next(m)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Run Code Online (Sandbox Code Playgroud)

它可以list看到StopIteration并使用它来停止根据收益构建列表map

另一方面,列表理解是通过迭代 来构建列表,而不是列表iterators中的特定迭代器。也就是说,用于为列表生成一个,而不是确定我们是否已到达 的末尾。next(it)iterators