What is the difference between i += 2 and i = i + 2?

Asked

Viewed 634 times

16

I was seeing, there are people who speak that is different and there are those who speak that is the same thing. I am confused. They are different or do the same thing?

  • 1

    No difference in result. The first form is only more compact.

  • 4

    The first calls the method __iadd__; the second method __add__. The result produced is the same for integer if none of these methods is overwritten.

  • The only thing I’ve ever heard is that the auto increment metod is faster by not having to allocate twice the space in memory, apart from that there is no difference and maybe its impact on peformance is not so great depending on the size of the processing

  • I did both and gave different results in two lists. The first way: a = [1, 2, 3]
b = a
b += [1, 2, 3]
print(a) # [1, 2, 3, 1, 2, 3]
print(b) # [1, 2, 3, 1, 2, 3] The second way: a = [1, 2, 3] b = a b = b + [1, 2, 3] print(a) # [1, 2, 3] print(b) # [1, 2, 3, 1, 2, 3]

4 answers

16

As already commented, there will be no difference in the result.

But we will do a simple debugging of your code:

Using i += 2

from dis import dis

code = '''
i=1
i+=2

'''

print(dis(code))

 2       0 LOAD_CONST        0 (1)
         3 STORE_NAME        0 (i)

 3       6 LOAD_NAME         0 (i)
         9 LOAD_CONST        1 (2)
         12 INPLACE_ADD
         13 STORE_NAME       0 (i)
         16 LOAD_CONST       2 (None)
         19 RETURN_VALUE
None  

Using i = i + 2

from dis import dis

code = '''
i=1
i=i+2

'''

print(dis(code))

 2       0 LOAD_CONST        0 (1)
         3 STORE_NAME        0 (i)

 3       6 LOAD_NAME         0 (i)
         9 LOAD_CONST        1 (2)
         12 BINARY_ADD
         13 STORE_NAME       0 (i)
         16 LOAD_CONST       2 (None)
         19 RETURN_VALUE
None 

Note that the only difference is between the instructions INPLACE_ADD and BINARY_ADD

Translating, via google Translate, the question:

When is "i += x" Different from "i = i + x" in Python?

When it is "i + = x" other than "i = i + x" in Python?

We’ll get to this reply, translated via google Translate:

It depends entirely on the object i.

+=calls the __iadd__method (if it exists - running __add__if not exist) as long as +calls the __add__method¹ or the __radd__method in some cases¹ .

From an API perspective, __iadd__is supposed to be used for modify mutable objects in place (returning the object that was mutated), while __add__must return a new instance of something. For objects immutable , the two methods return a new instance, but __iadd__will place the new instance in the current namespace with the same name as the old instance. That’s why

i = 1
i += 1

seems to increase i. In reality, you get a new integer and the attributes "on top of" i -- missing a reference to the integer former. In that case, i += 1 is exactly the same as i = i + 1.

But with most changeable objects, it’s a different story:

As a concrete example:

a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a  #[1, 2, 3, 1, 2, 3]
print b  #[1, 2, 3, 1, 2, 3]

compared to:

a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]

note how in the first example, once b and a refer to the same object, when use += in b, he really changes b(and a see the change also - After all, it is referencing a in the same list).

In the second case, however, when I do b = b + [1, 2, 3], that takes the list that b is making reference and a concatenates with a new list [1, 2, 3]. It then stores the concatenated list in the current namespace as b -- without considering what b was the line previous.

¹ In the expression x + y, if x.__add__is not implemented or x.__add__(y)returns NotImplemented and x and y have guys different , next, x + y tries to call y.Radd(x). So in case you have foo_instance += bar_instance

if Foo not implement __add__or __iadd__ then the result here is the same as

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

² In the expression foo_instance + bar_instance, bar_instance.__radd__will be tried before foo_instance.__add__ if the type of bar_instance is a subclass of the foo_instance(eg issubclass(Bar, Foo)). The rationale for this is because Bar is in certain a "high level" object that Foo thus Bar must obtain the option to replace the behavior of Foo.

9


I found something interesting on the PEP-203 which is where they propose the Augmented assignment (i += 2):

The idea behind the increased assignment in Python is that it’s not just an easier way to write the common practice of storing the result of a binary operation in your left operand, but also a way for the operative of the left in question to know that it must operate on itself, instead of creating a modified copy of itself.

Source: https://www.python.org/dev/peps/pep-0203/#id8

In my conclusion, an important difference is that in the increased assignment it might not create a modified copy of itself, for optimization purposes.

  • 3

    Your summary conclusion is not correct, and can be dangerous. For immutable objects - which includes Python numeric types, the increased assignment creates a new object likewise. For mutable objects, such as lists, and then dictionaries (the operation of "+" with dictionaries was accepted for Python 3.9), this assignment modifies the object prodio.

  • Edited! Thanks for the comment!

  • Edited the response to reflect the fact that += can avoid the creation of an object, does not mean that going avoid (or which must be avoided).

  • @epx yes, but this is not valid for strings as you suggested in your reply.

  • 1

    https://www.codementor.io/satwikkansal/do-you-really-think-you-know-strings-in-python-fnxh8mtha suggests that it is valid yes.

  • @epx In which part?

Show 1 more comment

-1

In the case of a number there is not much difference, but if it was a more complex type, it may be that += would be more efficient than + because it does not need to create a new object.

For example, suppose it is the type String,

a = a + b

in fact what happens behind the scenes is:

tmp = a + b
a = tmp

The string "tmp" is completely new, and for a brief period coexists with "a" in memory.

Already the expression

a += b

can be optimized to work directly on the "entrails" of the string "a" in order to attach the contents of "b", as it is clear that the original value of "a" does not matter anymore.

Even though the string is an immutable type in Python and many other languages, this is a case where it can be changeable internally.

I cited the type string only as an example, it may or may not take advantage of this difference between operators. The fact is that Python allows you to do this type of optimization by implementing your type or class, implementing the __iadd__ method beyond __add__, assuming of course that the "add" operation makes sense to it.

  • 1

    How is it possible to get a changeable string internally? I don’t understand this part.

  • That is there within the implementation; for human consumption it is immutable.

  • In Java has some Stringio type deals that play role of mutable string, must have something similar to Pyhthon.

  • 2

    Do you have sources to back up this information? I’ve been over and over the Python C source and I don’t remember ever seeing references to that possible Python changeability string, nor how this could influence the difference in the call of operators.

  • I said that an implementation CAN optimize by discriminating between operators += and +. If Python (or the Python C implementation; has pypy, has Ironpython, has others) does this, it is outside the scope of the question.

  • Besides, I used the native String type as an example. You can create a new type, or a class, and implement __iadd__ optimally in relation to __add__.

  • 2

    Well, then I’ll keep the negative; if the question is "how does it work in Python", I don’t see how useful an answer like "I don’t know what it’s like in Python, but it could be like this..."

  • This conclusion is wrong and the test is simple to just manipulate the references for a string: 1) create a string called a: >>> a = "teste". 2) It is done b a reference to a: >>> b = a. 3) If += modifies the string’s internal structure by not creating a new object, so we conclude that if we do >>> a += " mais", a and b will continue to reference the same object and both >>> print(a) and >>> print(b) print the same result. 4) Conclusion >>> print(a) printed teste mais and >>> print(b) printed teste implying that >>> a += " mais" created a new object in a.

  • String in Python is an immutable type. Your test does not prove that optimization is not done. Any decent String implementation implements internal reference count and copy-on-write. The only thing your test proves is that the implementation is ok, which is not exactly a novelty.

  • I found this article: https://www.codementor.io/satwikkansal/do-you-really-think-you-know-strings-in-python-fnxh8mtha snippet: += is Actually Faster than + for concatenating more than two strings because the first string (example, S1 for S1 += s2 + S3) is not destroyed while calculating the complete string.

Show 5 more comments

-4

There is no difference as to the results, only in the writing mode, one being more summarized and the other not. Thus, both can be used, as there will be no change in any results.

  • 2

    Monteiro, I invite you to read Luiz Augusto’s answer: https://answall.com/a/402702/5878

Browser other questions tagged

You are not signed in. Login or sign up in order to post.