Why is 'Extended Iterable Unpacking' not working for empty strings?

时间:2015-06-25 10:02:24

标签: python python-3.x iterable-unpacking

Why is

>>> a, *b = '' 

not possible, when

>>> a, *b = ' '
>>> a, b
(' ', [])  # b == empty list here anyway.

and

>>> type('')
<class 'str'>

I mean, why isn't it

>>> a, *b = ''
>>> a, b  # a could == ''
('', [])

2 个答案:

答案 0 :(得分:1)

因为指定了一个强制变量。

右侧应至少有一个项目(一个字符用于字符串)。

根据their answer

  

简单赋值左侧的元组(或列表)(解包   没有为增强赋值定义)最多可以包含一个   表达前面加上一个星号(此后为   称为“已加星标”的表达式,表示列表中的其他表达式   被称为“强制性”)。这表示将是一个子表达式   分配了正在解压缩的迭代中的所有项目的列表   未分配给任何强制性表达式,如果是,则分配为空列表   没有这样的物品。

答案 1 :(得分:0)

基于PEP 3132

  

unpack_iterable()中的函数ceval.c被更改为通过argcntafter参数处理扩展解包。在UNPACK_EX案例中,该函数将执行以下操作:

  • 在加星标的
  • 之前收集所有必填项目
  • 从列表弹出项目
  • 中收集iterable中的所有剩余项目
  • 从列表中加星标后的强制目标推送单个 项目和堆栈上已调整大小的列表

所以它会在第一步失败,因为你的字符串中没有强制目标。

有关详细信息,请查看unpack_iterable中的caval.c

unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
{
    int i = 0, j = 0;
    Py_ssize_t ll = 0;
    PyObject *it;  /* iter(v) */
    PyObject *w;
    PyObject *l = NULL; /* variable list */

    assert(v != NULL);

    it = PyObject_GetIter(v);
    if (it == NULL)
        goto Error;

    for (; i < argcnt; i++) {
        w = PyIter_Next(it);
        if (w == NULL) {
            /* Iterator done, via error or exhaustion. */
            if (!PyErr_Occurred()) {
                if (argcntafter == -1) {
                    PyErr_Format(PyExc_ValueError,
                        "not enough values to unpack (expected %d, got %d)",
                        argcnt, i);
                }
                else {
                    PyErr_Format(PyExc_ValueError,
                        "not enough values to unpack "
                        "(expected at least %d, got %d)",
                        argcnt + argcntafter, i);
                }
            }
            goto Error;
        }
        *--sp = w;
    }

    if (argcntafter == -1) {
        /* We better have exhausted the iterator now. */
        w = PyIter_Next(it);
        if (w == NULL) {
            if (PyErr_Occurred())
                goto Error;
            Py_DECREF(it);
            return 1;
        }
        Py_DECREF(w);
        PyErr_Format(PyExc_ValueError,
            "too many values to unpack (expected %d)",
            argcnt);
        goto Error;
    }

    l = PySequence_List(it);
    if (l == NULL)
        goto Error;
    *--sp = l;
    i++;

    ll = PyList_GET_SIZE(l);
    if (ll < argcntafter) {
        PyErr_Format(PyExc_ValueError,
            "not enough values to unpack (expected at least %d, got %zd)",
            argcnt + argcntafter, argcnt + ll);
        goto Error;
    }

    /* Pop the "after-variable" args off the list. */
    for (j = argcntafter; j > 0; j--, i++) {
        *--sp = PyList_GET_ITEM(l, ll - j);
    }
    /* Resize the list. */
    Py_SIZE(l) = ll - argcntafter;
    Py_DECREF(it);
    return 1;

Error:
    for (; i > 0; i--, sp++)
        Py_DECREF(*sp);
    Py_XDECREF(it);
    return 0;
}