[英]Why does “TypeError: cannot unpack non-iterable int object” occur when trying to unpack tuples?
[英]Why does unpacking a chain with a non-iterable argument raise this error?
考虑以下代码:
from itertools import chain list(chain(42))
我将一个不可迭代的参数传递给chain
并且毫不奇怪,我得到了这个错误:
TypeError: 'int' object is not iterable
(仅因为chain
在实际迭代之前才评估其参数,所以传递到list
是唯一必要的。)
如果正确使用chain
,则可以将结果作为函数参数解压缩:
from itertools import chain foo = lambda x: x foo(*chain([42]))
这没有错误运行。
现在,考虑以上两种情况的组合,即,具有不可迭代参数的链被解压缩为函数参数:
from itertools import chain foo = lambda x: x foo(*chain(42))
不出所料,这失败了。 在Python 3中,这将引发与第一种情况相同的错误。 但是,在Python 2.7.12中,抛出的错误是:
TypeError: <lambda>() argument after * must be an iterable, not itertools.chain
这对我来说没有任何意义。 itertools.chain
显然是一个可迭代的类型: isinstance(chain(42),collections.Iterable)
产生True
。 同样,在第二个示例中它也没有引起任何问题。 我期望与情况2或Python 3类似的错误消息。此错误消息的解释是什么?
您看到的行为是试图给出更清晰的错误消息,说明函数调用出了什么问题。
Python 2.7确定对象是否可迭代的方法只是尝试对其进行迭代,然后在必要时捕获TypeError
异常。 它实际上并没有在Python代码中实现,但这仍然是处理函数调用语法时发生的事情。 注意:这与lambda
无关,一个普通的def
也将说明该示例。
这个C代码在CPython 2.7中处理了函数调用:
static PyObject *
ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
{
... snip ...
t = PySequence_Tuple(stararg);
if (t == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError) &&
/* Don't mask TypeError raised from a generator */
!PyGen_Check(stararg)) {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after * "
"must be an iterable, not %200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
stararg->ob_type->tp_name);
}
goto ext_call_fail;
... snip ...
}
为了简洁起见,我已将代码截断以显示相关的块:将starargs迭代为一个元组,如果PyExc_TypeError
失败,则类型和消息与您所看到的匹配的消息将引发新的错误。
在Python 3中,函数调用C代码已被清理和简化。 实际上, ext_do_call
函数甚至不再存在,它可能在PEP 3113的实现过程中被删除了。 现在,反复处理断链的异常会冒出未处理的泡沫。 如果您想在当前的调用代码中四处浏览,则可以开始在Python/ceval.c::do_call_core
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.