Разница между + = и __iadd__ [duplicate]

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

Хорошие новости заключается в том, что, если вы хорошо понимаете этот момент, вам никогда не придется беспокоиться о гоночных условиях. Прежде всего вы должны понимать, как вы хотите упорядочить свой код как по существу ответ на разные дискретные события, и как вы хотите объединить их в логическую последовательность. Вы можете использовать обещания или новые асинхронные / ожидающие более высокие уровни в качестве инструментов для этой цели, или вы можете откатывать свои собственные.

Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.

8
задан wim 7 April 2015 в 01:36
поделиться

3 ответа

Вы всегда можете изменить изменяемое значение внутри кортежа. Непонятное поведение, которое вы видите с помощью

>>> thing[0] += 'd'

, вызвано +=. Оператор += выполняет добавление на месте, но также присваивает - дополнение на месте работает только с файлом, но присваивание не выполняется, поскольку кортеж является неизменным. Думать об этом, как

>>> thing[0] = thing[0] + 'd'

, объясняет это лучше. Мы можем использовать модуль dis из стандартной библиотеки, чтобы посмотреть на байт-код, сгенерированный из обоих выражений. С += мы получаем байт-код INPLACE_ADD:

>>> def f(some_list):
...     some_list += ["foo"]
... 
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (some_list)
              3 LOAD_CONST               1 ('foo')
              6 BUILD_LIST               1
              9 INPLACE_ADD         
             10 STORE_FAST               0 (some_list)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE        

С + получаем a BINARY_ADD:

>>> def g(some_list):
...     some_list = some_list + ["foo"]
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (some_list)
              3 LOAD_CONST               1 ('foo')
              6 BUILD_LIST               1
              9 BINARY_ADD          
             10 STORE_FAST               0 (some_list)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE        

Обратите внимание, что мы получаем STORE_FAST в обоих местах. Это байт-код, который терпит неудачу, когда вы пытаетесь сохранить обратно в кортеж - INPLACE_ADD, который появляется перед началом работы.

Это объясняет, почему случай «Не работает и работает» оставляет измененный список позади: кортеж уже имеет ссылку на список:

>>> id(thing[0])
3074072428L

Список затем изменен с помощью INPLACE_ADD и STORE_FAST:

>>> thing[0] += 'd'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Таким образом, кортеж все еще имеет ссылку на тот же список, но список был изменен в -place:

>>> id(thing[0])
3074072428L
>>> thing[0] 
['b', 'c', 'd']
7
ответ дан Martin Geisler 24 August 2018 в 21:22
поделиться

Вы не можете изменять кортеж, но вы можете изменить содержимое вещей, содержащихся в кортеже. Списки (вместе с наборами, dicts и объектами) являются ссылочным типом , и, таким образом, «вещь» в кортеже является просто ссылкой - фактический список является изменяемым объектом, на который указывает эта ссылка и может быть изменен без изменения самой ссылки.

( + ,)       <--- your tuple (this can't be changed)
  |
  |
  v
 ['a']       <--- the list object your tuple references (this can be changed)

После thing[0][0] = 'b':

( + ,)       <--- notice how the contents of this are still the same
  |
  |
  v
 ['b']       <--- but the contents of this have changed

После thing[0].append('c'):

( + ,)       <--- notice how this is still the same
  |
  |
  v
 ['b','c']   <--- but this has changed again

Причина, по которой ошибки += заключаются в том, что она не полностью эквивалентна .append() - на самом деле это добавление, а затем назначение (и присваивание не выполняется), а не просто добавление на место .

2
ответ дан Amber 24 August 2018 в 21:22
поделиться

Вы не можете заменить элемент кортежа, но вы можете заменить все содержимое элемента. Это будет работать:

thing[0][:] = ['b']
1
ответ дан Lawrence D'Oliveiro 24 August 2018 в 21:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: