python - Python3: Does the built-in function "map" have a bug?
问题描述
The following I had with Python 3.8.1 (on macOS Mojave, 10.14.6, as
well as Python 3.7 (or some older) on some other platforms). I'm new
to computing and don't know how to request an improvement of a
language, but I think I've found a strange behaviour of the built-in
function map
.
As the code next(iter(()))
raises StopIteration
, I expected to
get StopIteration
from the following code:
tuple(map(next, [iter(())]))
To my surprise, this silently returned the tuple ()
!
So it appears the unpacking of the map object stopped when
StopIteration
came from next
hitting the "empty" iterator
returned by iter(())
. However, I don't think the exception was
handled right, as StopIteration
was not raised before the "empty"
iterator was picked from the list (to be hit by next
).
- Did I understand the behaviour correctly?
- Is this behaviour somehow intended?
- Will this be changed in a near future? Or how can I get it?
Edit: The behaviour is similar if I unpack the map object in different ways, such as by list
, for for-loop, unpacking within a list, unpacking for function arguments, by set
, dict
. So I believe it's not tuple
but map
that's wrong.
Edit: Actually, in Python 2 (2.7.10), the "same" code raises
StopIteration
. I think this is the desirable result (except that map
in this case does not return an iterator).
解决方案
这不是map
错误。这是 Python 决定依赖异常来控制流的一个丑陋的结果:实际错误看起来像正常的控制流。
当map
呼叫next
时iter(())
,next
加注StopIteration
。这StopIteration
传播出map.__next__
和进入tuple
呼叫。这StopIteration
看起来像StopIteration
通常map.__next__
会引发地图结束的信号,因此tuple
认为地图只是没有元素。
这会导致比你看到的更奇怪的后果。例如,map
当映射函数引发异常时,迭代器不会将自身标记为耗尽,因此您甚至可以在之后继续迭代它:
m = map(next, [iter([]), iter([1])])
print(tuple(m))
print(tuple(m))
输出:
()
(1,)
(CPythonmap
实现实际上并没有办法将自己标记为耗尽 - 它依赖于底层迭代器。)
这种 StopIteration 问题很烦人,以至于他们实际上改变了生成器的 StopIteration 处理来缓解它。StopIteration 过去通常从生成器传播出去,但是现在,如果 StopIteration 会从生成器传播出去,它会被 RuntimeError 替换,因此它看起来不像生成器正常结束。不过,这只影响生成器,不会影响其他迭代器,例如map
.
推荐阅读
- java - TestContainers SQL 连接数过多异常
- python - Zapier 代码:Python,生成 CSV 字符串
- sqlalchemy - 使用 SQLAlchemy 迁移数据库
- ansible - ansible-playbook 中的 yml 语法不正确
- swift - 活动编译条件不起作用
- java - java 无法为标签 fmt:bundle 加载标签处理程序类
- amazon-ecs - 使用相同的 Fargate 容器运行从 AWS Step Functions 执行不同的步骤
- selenium - 如何使用 xpath 自动单击
- javascript - Gatsby:WebpackError [React Intl] 找不到所需的“intl”对象。
需要存在于组件祖先中 - javascript - 如何从回调中返回值?