Если x является списком, то почему x + = "ha" работает, а x = x + "ha" выдает исключение?
Из того, что я знаю, + op для списков требует, чтобы второй операнд был итерируемым, что "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
Ответы
Ответ 1
Использование +=
со списком похоже на вызов extend
, а не +
.
- Вы можете вызвать
extend
с помощью итерации.
- Вы можете использовать только
+
с другим списком.
Я могу только догадываться, почему это решение было принято, но я думаю, что это по соображениям производительности. Вызов +
приводит к созданию нового объекта и копированию всех элементов, тогда как 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 ...
Ответ 2
Ты думаешь об этом назад. Вы спрашиваете, почему x = x + 'ha'
создает исключение, учитывая, что работает x += 'ha'
. В самом деле, вопрос в том, почему x += 'ha'
работает вообще.
Все согласны (надеюсь), что 'abc' + 'ha'
и [1, 2, 3] + ['h', 'a']
должны работать. И в этих случаях перегрузка +=
, чтобы сделать модификацию на месте, кажется разумной.
Разработчики языка решили, что [1, 2, 3] + 'ha'
не должен, потому что вы смешиваете разные типы. И это тоже кажется разумным.
Поэтому возникает вопрос, почему они решили разрешить смешивание разных типов в случае x += 'ha'
. В этом случае, я думаю, есть несколько причин:
- Это удобная стрижка
- Очевидно, что происходит (вы добавляете каждый из элементов в iterable в
x
)
В общем, Python пытается позволить вам делать то, что вы хотите, но там, где есть двусмысленность, он стремится заставить вас быть явным.
Ответ 3
При определении операторов существуют два разных оператора "add": один называется __add__
, другой __iadd__
. Последнее относится к дополнениям на месте с +=
, а другой является регулярным оператором +
. http://docs.python.org/reference/datamodel.html содержит больше информации об этом.