如果x是list,为什么x + ="ha"可以工作,而x = x +"ha"会抛出异常?

mas*_*ley 46 python list operators

从我所知的很少,+ op for lists只需要第二个操作数可迭代,"ha"显然是.

在代码中:

>>> x = []
>>> x += "ha"
>>> x
['h', 'a']
>>> x = x + "ha"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 31

使用+=列表就像打电话extend,而不是+.

  • 你可以extend使用iterable 调用.
  • 您只能使用+其他列表.

我只能猜到为什么做出这个决定,但我想这是出于性能原因.调用会+导致创建一个新对象并复制所有项目,而extend在某些情况下可以使用现有列表对象中的可用空间来保存副本.

这个决定的另一个副作用是,如果你写x += y了对列表的其他引用将看到更改,但如果你使用,x = x + y那么他们不会.这在下面说明:

>>> x = ['a','b']
>>> y = ['c', d']
>>> z = x
>>> x += y
>>> z
['a', 'b', 'c', 'd']

>>> x = ['a','b']
>>> y = ['c', d']
>>> z = x
>>> x = x + y
>>> z
['a', 'b']

参考

用于列表的Python源代码.

源代码+=:

static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
    PyObject *result;

    result = listextend(self, other);
    if (result == NULL)
        return result;
    Py_DECREF(result);
    Py_INCREF(self);
    return (PyObject *)self;
}

源代码+:

static PyObject *
list_concat(PyListObject *a, PyObject *bb)
{
    Py_ssize_t size;
    Py_ssize_t i;
    PyObject **src, **dest;
    PyListObject *np;
    if (!PyList_Check(bb)) {
        PyErr_Format(PyExc_TypeError,
                  "can only concatenate list (not \"%.200s\") to list",
                  bb->ob_type->tp_name);
        return NULL;
    }

    // etc ...

  • 我认为这里真正的问题是,"为什么会出现这种不一致?" (20认同)
  • 我不认为这个问题是对设计的批评.第一步必须是了解如何实现不一致,这就是我们在这里可以提供的帮助.如果你问我:)你评论者提出的更大问题完全超出了SO的范围. (5认同)
  • 哇,真是个好消息.同时,我通过我正在阅读的PDF进行搜索,它实际上说+是concat而+ =是extend().唯一的问题是它在引入+ op之后说了~300页!而且我必须承认这是一个真正的震撼,因为其他一切都非常直观(至今无论如何).谢谢! (2认同)

Chr*_* B. 8

你正在考虑倒退.你问为什么x = x + 'ha'抛出异常,因为它x += 'ha'有效.真的,问题是为什么要x += 'ha'工作.

每个人都同意(我希望)'abc' + 'ha'并且[1, 2, 3] + ['h', 'a']应该工作.在这些情况下,+=进行就地修改的重载似乎是合理的.

语言设计师决定不[1, 2, 3] + 'ha'应该,因为你混合了不同的类型.这看起来也很合理.

所以问题是为什么他们决定允许混合不同类型的情况x += 'ha'.在这种情况下,我想有几个原因:

  • 这是一个方便的速记
  • 很明显会发生什么(你将迭代中的每个项追加到x)

一般来说,Python试图让你做你想做的事情,但是如果有歧义,它往往会迫使你明确.

  • 我认为这里的重点是它不是*显而易见的问题.在大多数定义了`+ =`和`+`的编程语言中,做'x + = y`通常被定义为与`x = x + y`完全相同.实际上,通常一个是另一个的别名. (6认同)
  • 另一个试探性的-1:对我来说很明显,对于任何"x"和"y","x + = y"被定义为"x = x + y".很明显你已经避免回答这个问题了.;) (2认同)
  • 恕我直言,通常如果x = x + y会产生预期的效果,x + = y也应该如此.然而,相反的情况并非如此.可以构造一个对象,以便如果两个线程同时执行"x + = y;" 和"x + = z;" 结果将与按某种顺序执行的语句相同,但如果它们执行"x = x + y;" 和"x = x + z;" 没有实际的方法来提供这样的保证. (2认同)
  • "只是某个人"让我非常希望有能力进行评论. (2认同)

小智 5

定义运算符时,有两个不同的"添加"运算符:一个被调用__add__,另一个被调用__iadd__.后者用于就地添加+=,另一个是常规+操作符.http://docs.python.org/reference/datamodel.html上有更多信息.