Действительно ли я = я + n совпадает с я + = n? - программирование
Подтвердить что ты не робот

Действительно ли я = я + n совпадает с я + = n?

Один блок кода работает, а другой нет. Что имело бы смысл, за исключением того, что второй блок такой же, как первый, только с записанной на нем операцией. Они практически одинаковые операции.

l = ['table']
i = []

Версия 1

for n in l:
    i += n
print(i)

Вывод: ['t', 'a', 'b', 'l', 'e']

Версия 2

for n in l:
    i = i + n
print(i)

Выход:

Ошибка типа: можно только объединить список (не "str") в список


Что вызывает эту странную ошибку?

4b9b3361

Ответ 1

Они не должны быть одинаковыми.

Использование оператора + вызывает метод __add__ а использование оператора += вызывает __iadd__. Это полностью зависит от рассматриваемого объекта, что происходит при вызове одного из этих методов.

Если вы используете x += y но x не предоставляет метод __iadd__ (или метод возвращает NotImplemented), __add__ используется как запасной вариант, что означает, что x = x + y происходит.

В случае списков использование l += iterable фактически расширяет список l элементами iterable. В вашем случае каждый символ из строки (который является итеративным) добавляется во время операции extend.

Демонстрация 1: использование __iadd__

>>> l = []
>>> l += 'table'
>>> l
['t', 'a', 'b', 'l', 'e']

Демонстрация 2: использование extend делает тоже самое

>>> l = []
>>> l.extend('table')
>>> l
['t', 'a', 'b', 'l', 'e']

Демонстрация 3: добавление списка и строки вызывает TypeError.

>>> l = []
>>> l = l + 'table'
[...]
TypeError: can only concatenate list (not "str") to list

Не используя += дает TypeError здесь, потому что только __iadd__ реализует простирающееся поведение.

Демонстрация 4: общая ловушка: += не создает новый список. Мы можем подтвердить это, проверив идентичность объектов с помощью оператора is.

>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l += [1, 2, 3] # uses __iadd__, mutates l in-place
>>> l is l_ref # confirm that l and l_ref are names for the same object
True
>>> l
[1, 2, 3]
>>> l_ref # mutations are seen across all names
[1, 2, 3]

Однако l = l + iterable синтаксис l = l + iterable новый список.

>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l = l + [1, 2, 3] # uses __add__, builds new list and reassigns name l
>>> l is l_ref # confirm that l and l_ref are names for different objects
False
>>> l
[1, 2, 3]
>>> l_ref
[]

В некоторых случаях это может привести к незначительным ошибкам, поскольку += изменяет исходный список, в то время как
l = l + iterable создает новый список и переназначает имя l.

БОНУС

Нед Батчелдер вызов, чтобы найти это в документах

Ответ 2

Если во втором случае вы оберните список вокруг n чтобы избежать ошибок:

for n in l:
    i = i + [n]
print(i)

ты получаешь

['table']

Так что это разные операции.

Ответ 3

Нет.

7.2.1. Расширенные операторы присваивания:

Расширенное выражение присваивания, такое как x += 1 может быть переписано как x = x + 1 для достижения аналогичного, но не совсем равного эффекта. В расширенной версии x оценивается только один раз. Кроме того, когда это возможно, фактическая операция выполняется на месте, что означает, что вместо создания нового объекта и назначения его цели, старый объект вместо этого изменяется.