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