简体   繁体   English

为什么解开带有不可迭代参数的链会引发此错误?

[英]Why does unpacking a chain with a non-iterable argument raise this error?

  1. Consider the following code: 考虑以下代码:

     from itertools import chain list(chain(42)) 

    I am passing a non-iterable as an argument to chain and little surprisingly, I get exactly this error: 我将一个不可迭代的参数传递给chain并且毫不奇怪,我得到了这个错误:

     TypeError: 'int' object is not iterable 

    (Passing to list is only necessary because chain does not evaluate its arguments until the actual iteration.) (仅因为chain在实际迭代之前才评估其参数,所以传递到list是唯一必要的。)

  2. If I use chain correctly, I can unpack the result as function argument: 如果正确使用chain ,则可以将结果作为函数参数解压缩:

     from itertools import chain foo = lambda x: x foo(*chain([42])) 

    This runs without errors. 这没有错误运行。

  3. Now, consider the combination of the two above cases, ie, a chain with a non-iterable argument unpacked as function arguments: 现在,考虑以上两种情况的组合,即,具有不可迭代参数的链被解压缩为函数参数:

     from itertools import chain foo = lambda x: x foo(*chain(42)) 

    As expected, this fails. 不出所料,这失败了。 In Python 3 this throws the same error as the first case. 在Python 3中,这将引发与第一种情况相同的错误。 However, in Python 2.7.12, the error thrown is: 但是,在Python 2.7.12中,抛出的错误是:

     TypeError: <lambda>() argument after * must be an iterable, not itertools.chain 

    This does not make any sense to me. 这对我来说没有任何意义。 itertools.chain clearly is an iterable type: isinstance(chain(42),collections.Iterable) yields True . itertools.chain显然是一个可迭代的类型: isinstance(chain(42),collections.Iterable)产生True Also, it did not cause any problem in the second example. 同样,在第二个示例中它也没有引起任何问题。 I would expect a similar error message as in case 2 or Python 3. What is the explanation for this error message? 我期望与情况2或Python 3类似的错误消息。此错误消息的解释是什么?

The behaviour you are seeing is an attempt to give a clearer error message about what went wrong with the function call. 您看到的行为是试图给出更清晰的错误消息,说明函数调用出了什么问题。

Python 2.7's way of determining if an object is iterable is just attempting to iterate it, and then catch the TypeError exception if necessary. Python 2.7确定对象是否可迭代的方法只是尝试对其进行迭代,然后在必要时捕获TypeError异常。 It's not actually implemented in Python code, but that's still what happens in handling the function call syntax. 它实际上并没有在Python代码中实现,但这仍然是处理函数调用语法时发生的事情。 Note: this has nothing to do with lambda , and a plain old def would have illustrated the example as well. 注意:这与lambda无关,一个普通的def也将说明该示例。

The function call is handled in CPython 2.7 by this C code : 这个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 ...
}

I've truncated the code for brevity to show the relevant block: the starargs are iterated into a tuple, and if that fails with PyExc_TypeError then a new error is raised with the type and message matching what you've seen. 为了简洁起见,我已将代码截断以显示相关的块:将starargs迭代为一个元组,如果PyExc_TypeError失败,则类型和消息与您所看到的匹配的消息将引发新的错误。

In Python 3, the function call C code was cleaned up and simplified significantly. 在Python 3中,函数调用C代码已被清理和简化。 Actually the ext_do_call function doesn't even exist any more, it was likely removed during implementation of PEP 3113 . 实际上, ext_do_call函数甚至不再存在,它可能在PEP 3113的实现过程中被删除了。 Now the exception from iterating a broken chain bubbles up unhandled. 现在,反复处理断链的异常会冒出未处理的泡沫。 If you want to poke around in the current call code, you may start digging in Python/ceval.c::do_call_core . 如果您想在当前的调用代码中四处浏览,则可以开始在Python/ceval.c::do_call_core

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么在尝试解包元组时会出现“TypeError: cannot unpack non-iterable int object”? - Why does “TypeError: cannot unpack non-iterable int object” occur when trying to unpack tuples? 为什么我的生成器 function 变成了不可迭代的浮点数 object? - Why does my generator function turned into a non-iterable float object? 为什么我会收到此错误“无法解压缩不可迭代的 NoneType 对象”? - Why am I receiving this error "cannot un-pack non-iterable NoneType object"? 为什么Python用参数引发问题需要解压缩? - Why does Python raise with arguments needs unpacking? 为什么 Python 允许解压缩空的可迭代对象? - Why does Python allow unpacking an empty iterable? 如何修复“无法解压不可迭代的 NoneType 对象”错误 - How to fix "cannot unpack non-iterable NoneType object" error 如何修复python中无法解包的不可迭代错误 - how to fix cannot unpack non-iterable error in python 无法在 Python 中解压不可迭代的方法对象错误 - Cannot unpack non-iterable method object error in Python 得到一个错误 TypeError: cannot unpack non-iterable float object - Getting an error TypeError: cannot unpack non-iterable float object TypeError:无法解压不可迭代的 NoneType 对象错误 - TypeError: cannot unpack non-iterable NoneType object Error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM