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