Подтвердить что ты не робот

Python Разница между x = x + 1 и x + = 1

В Python существует ли какая-либо разница (семантика, эффективность и т.д.) между написанием x = x+1 и x += 1?

4b9b3361

Ответ 1

Да. В зависимости от того, как кодируется класс x, короткая форма имеет возможность изменять x на месте вместо того, чтобы создавать новый объект, представляющий сумму, и возвращать его обратно к тому же имени. Это имеет значение, если у вас есть несколько переменных, все ссылающиеся на один и тот же объект - например, со списками:

>>> a = b = []
>>> a += [5]
>>> a
[5]
>>> b
[5]
>>> a = a + [5]
>>> a
[5, 5]
>>> b
[5]

Это происходит потому, что за кулисами операторы называют разные магические методы: + вызывает __add__ или __radd__ (которые, как ожидается, не изменят ни один из их аргументов), и += try __iadd__ (который разрешено изменять self, если это похоже на него), прежде чем возвращаться к логике +, если __iadd__ не существует.

Ответ 2

Они почти одинаковы для целых чисел и float, но для lists:

lis = lis+['foo'] создает новый список путем объединения lis и ['foo'], а затем присваивает результат lis

и:

lis += [foo] эквивалентен lis.extend([foo])

>>> lis = [1,2,3]
>>> id(lis)
3078880140L
>>> lis += ['foo']   #or lis.extend(['foo'])
>>> id(lis)          #same object
3078880140L


>>> lis = [1,2,3]
>>> id(lis)
3078880076L
>>> lis = lis+['foo']
>>> id(lis)            #new object
3078880012L

Ответ 3

Да, это разные операторы, которые компилируются в разные байт-коды:

>>> import dis
>>> def test1(x):
...    x = x + 1
... 
>>> def test2(x):
...    x += 1
... 
>>> dis.dis(test1)
  2           0 LOAD_FAST                0 (x) 
              3 LOAD_CONST               1 (1) 
              6 BINARY_ADD           
              7 STORE_FAST               0 (x) 
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE         
>>> dis.dis(test2)
  2           0 LOAD_FAST                0 (x) 
              3 LOAD_CONST               1 (1) 
              6 INPLACE_ADD          
              7 STORE_FAST               0 (x) 
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE         

В этом случае это не будет иметь большого значения, поскольку int являются неизменяемыми. Теоретически они могут быть реализованы по-разному (в зависимости от интерпретатора), но это не изменит способ работы с этим значением.

В общем, они могут быть реализованы для выполнения совершенно разных вещей (+ реализуется магическим методом __add__() и += с помощью __iadd()__)), например, в большинстве изменяемых контейнеров он делает огромную разница, если у вас есть разные имена, ссылающиеся на один и тот же объект:

>>> x = []
>>> y = x
>>> x += [1]
>>> y
[1]
>>> x = x + [1]
>>> y
[1]
>>> x
[1, 1]

Вы можете видеть, что когда мы назначаем x на y, они оба указывают на один и тот же список. Когда мы используем +=, мы расширяем список и оба изменяем. Когда мы присваиваем новое значение x, y все еще указывает на оригинал и остается неизменным.

Ответ 4

Они разные, потому что для + и += существуют отдельные операторы. С x = x + 1 интерпретатор будет относиться к нему как x = x.__add__(1), а x += 1 будет x = x.__iadd(1), что может быть намного более эффективным, поскольку необязательно делать копию x.