首页 文章

为什么'Extended Iterable Unpacking'不能用于空字符串?

提问于
浏览
2

为什么是

>>> a, *b = ''

不可能,何时

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

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

我的意思是,为什么不呢

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

2 回答

  • 2

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

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


    根据PEP-3131

    简单赋值左侧的元组(或列表)(未为扩充赋值定义解包)最多可以包含一个前缀为单个星号的表达式(此后称为“星号”表达式,而其他表达式)在列表中称为“强制”) . 这指定一个子表达式,该子表达式将被分配一个列表,其中包含未被分配给任何强制表达式的可迭代迭代的所有项目,或者如果没有这样的项目,则为空列表 .

  • 1

    基于PEP 3132

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

    • 在加星标之前收集强制目标的所有项目

    • 从列表弹出项中的iterable中收集所有剩余项目
      列表中已加星标的列表之后的

    • 强制目标将单个项目和已调整大小的列表推送到堆栈上

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

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

    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;
    }
    

相关问题