If x is list, why does x += "ha" work, while x = x + "ha" throws an exception?
From what little I know, + op for lists only requires the 2nd operand to be iterable, which "ha" clearly is.
In code:
>>> 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
Using +=
with a list is like calling extend
, not +
.
- You can call
extend
with an iterable. - You can only use
+
with another list.
I can only guess why this decision was made, but I imagine it is for performance reasons. Calling +
results in a new object being created and all items being copied, whereas extend
can use free space in the existing list object saving a copy in some cases.
Another side-effect of this decision is that if you write x += y
other references to the list will see the change but if you use x = x + y
then they will not. This is demonstrated below:
>>> 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']
References
Python source code for list.
Source code for +=
:
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; }
Source code for +
:
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 ...
You're thinking about it backwards. You're asking why x = x + 'ha'
throws an exception, given that x += 'ha'
works. Really, the question is why x += 'ha'
works at all.
Everyone agrees (I hope) that 'abc' + 'ha'
and [1, 2, 3] + ['h', 'a']
should work. And in these cases, overloading +=
to do in-place modification seems reasonable.
The language designers decided that [1, 2, 3] + 'ha'
shouldn't, because you're mixing different types. And that seems reasonable as well.
So the question is why they decided to allow mixing different types in the case of x += 'ha'
. In this case, I imagine there are a couple reasons:
- It's a convenient shorthand
- It's obvious what happens (you append each of the items in the iterable to
x
)
In general, Python tries to let you do what you want, but where there's ambiguity, it tends to force you to be explicit.
When defining operators, there are two different "add" operators: One is called __add__
, the other __iadd__
. The latter one is for in-place additions with +=
, the other one is the regular +
operator. http://docs.python.org/reference/datamodel.html has more infos on that.
精彩评论