[英]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.