In Python, a small difference in how you write something can have big consequences. The difference between a = a + b and a += b in Python may look like a matter of style, but it can change how your program behaves. Both lines usually give you the same result. For example, when you add two integers, a = a + b (a simple assignment) and a += b (an augmented assignment) give the same answer.
But the two styles work differently inside Python, and with lists, that difference can change your program's output. In this guide, we compare the two with real code, explain what Python does behind the scenes, and show when the difference matters. Then we cover every assignment operator in Python, from = and += to //=, |=, and the walrus operator :=.
We ran every example on Python 3.13, and the output shown under each one is real. Memory IDs will be different on your computer.
Quick answer:
- For numbers, strings, and tuples,
a = a + banda += bbehave the same. The original value is never changed; the variable just points at the new result. - For lists (and other mutable types that support
+=, likebytearrayanddeque),a += bchanges the original object in place, whilea = a + bbuilds a brand-new list and pointsaat it. - That matters when two variables share the same list. With
+=, both see the change. Witha = a + b, onlyadoes.
In this guide:
Let's Find the Differences
Let's look at two code examples. The final results will look identical, but something important is different under the hood.
Using simple assignment "a = a + b"
# Initializing two lists
list1 = [1, 2, 3, 4, 5]
list2 = [6, 7, 8]
# Getting the ID of list1 before appending
id_before = id(list1)
print("Using simple assignment:")
# Append list2 to list1 using simple assignment
list1 = list1 + list2
# Getting the ID of list1 after appending
id_after = id(list1)
print(list1)
print("ID of list1 before appending:", id_before)
print("ID of list1 after appending: ", id_after)
Output:
Using simple assignment:
[1, 2, 3, 4, 5, 6, 7, 8]
ID of list1 before appending: 140503112761152
ID of list1 after appending: 140503113353152
In the above code, we created two lists, list1 and list2, and stored the starting ID of list1 for reference. The id() function returns a number that identifies an object in memory. Then we joined list2 onto list1 using simple assignment and checked the ID again.
list1 shows the expected values, but its ID changed. This proves that Python created a new list with the combined values and stored its reference in the variable list1.
Now let's run the same code using augmented assignment:
Using augmented assignment "a += b"
# Initializing two lists
list1 = [1, 2, 3, 4, 5]
list2 = [6, 7, 8]
# Getting the ID of list1 before appending
id_before = id(list1)
print("Using augmented assignment:")
# Append list2 to list1 using augmented assignment
list1 += list2
# Getting the ID of list1 after appending
id_after = id(list1)
print(list1)
print("ID of list1 before appending:", id_before)
print("ID of list1 after appending: ", id_after)
Output:
Using augmented assignment:
[1, 2, 3, 4, 5, 6, 7, 8]
ID of list1 before appending: 140693294055232
ID of list1 after appending: 140693294055232
We followed the same steps as before, but this time we used an augmented assignment. The ID of list1 stayed the same. Instead of creating a new list and storing its reference in list1, the += operator modified list1 in place and added the items of list2 to it.
What Is the Internal Working of Simple vs Augmented Assignment?
When you use simple assignment, with the syntax variable = expression, Python first calculates the value of the expression on the right, then points the variable on the left at the result. When a and b are lists, a + b builds a brand-new list, so the variable now refers to a new place in memory.
Augmented assignment, with the syntax variable op= expression (like += or *=), works differently. Here is what Python actually does with a += b:
- It checks whether the object in
ahas an in-place version of the operation. For+=, that is a special method called__iadd__(the "i" stands for in-place). - If it does, like a list, Python calls it. The object changes itself, and
akeeps pointing at the same object. - If it does not, like an
int,str, ortuple, Python falls back to normal addition (__add__) and pointsaat the result. That is exactly whata = a + bdoes.
You can check which types have the in-place version:
print(hasattr(list, "__iadd__")) # lists can change in place
print(hasattr(int, "__iadd__")) # ints cannot
print(hasattr(tuple, "__iadd__")) # tuples cannot
print(hasattr(str, "__iadd__")) # strings cannot
Output:
True
False
False
False
To summarize: simple assignment always computes a fresh result with normal addition and points the variable at it. Augmented assignment changes the original object in place when the object allows it, and otherwise behaves just like simple assignment.
Why the Difference Matters: Shared References
You might hope this detail never affects you as a programmer, but it does. In Python, two variables can point to the same list. Look at this:
# Initializing a list
list1 = [1, 2, 3, 4, 5]
# Storing its reference in two other variables
list2 = list1
list3 = list1
# Modifying list2 and list3
list2 = list2 + [6, 7, 8] # creates a new list and stores it in list2
list3 += [10, 11, 12] # changes the list that list1 and list3 share
print(list1)
print(list2)
print(list3)
Output:
[1, 2, 3, 4, 5, 10, 11, 12]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 10, 11, 12]
We created list1 and copied its reference into list2 and list3, so all three names pointed to the same list.
Then we added three numbers to list2 using simple assignment. That created a new list and stored it in list2, so list2 stopped pointing at the original list, and list1 was not affected.
But when we used augmented assignment on list3, it changed the shared list in place. Since list1 points to the same list as list3, printing list1 shows the new values too.
The same thing happens when you pass a list into a function. This is a very common source of "why did my list change?" bugs in assignments:
def add_bonus_new(scores):
scores = scores + [100] # builds a new list inside the function
def add_bonus_inplace(scores):
scores += [100] # changes the caller's list
grades = [85, 90]
add_bonus_new(grades)
print("After add_bonus_new:", grades)
add_bonus_inplace(grades)
print("After add_bonus_inplace:", grades)
Output:
After add_bonus_new: [85, 90]
After add_bonus_inplace: [85, 90, 100]
Inside add_bonus_new(), scores = scores + [100] builds a new list that only exists inside the function, so the caller's list is untouched. Inside add_bonus_inplace(), scores += [100] changes the caller's list directly.
This in-place behavior applies to other mutable types too. A bytearray and a collections.deque both support in-place +=. Sets do not support + at all, but they have in-place operators of their own, like |=, which you will see further down.
When They Behave the Same: Immutable Types
Augmented and simple assignment work the same way on immutable types, the types that cannot be changed after they are created, such as int, float, str, and tuple. Let's check this with code:
# Initializing an integer
a = 10
print("Original ID: ", id(a))
# Modifying the value using simple assignment
a = a + 10
print("After simple assign:", id(a))
# Modifying the value using augmented assignment
a += 10
print("After augmented: ", id(a))
Output:
Original ID: 10454568
After simple assign: 10454888
After augmented: 10455208
The ID of a changed after every update, no matter which style we used. Since an integer cannot be changed, Python points a at a different int object every time. (Small integers from -5 to 256 are even reused from a built-in cache, but the value 20 is still a different object from the value 10.)
The same is true for tuples and strings:
t = (1, 2, 3)
print(id(t))
t += (4,) # tuples cannot change, so Python builds a new tuple
print(id(t), t)
s = "Py"
t_alias = s
s += "thon" # strings cannot change either
print(s, t_alias) # the other name still sees the old string
Output:
140015644453184
140015644341440 (1, 2, 3, 4)
Python Py
The tuple got a new ID after +=. And because s += "thon" created a new string, the other name, t_alias, still sees the old value "Py". Compare that with the shared-list example above, where every name saw the change.
Which One Should You Use?
For lists, a += b is usually faster, because it only adds the new items to the existing list. a = a + b has to copy every item of a into a brand-new list first. Here is how they compare, where n is the length of a and m is the length of b:
a = a + b (simple) | a += b (augmented) | |
|---|---|---|
| Time | O(n + m): copies both lists into a new one | O(m) on average: only adds the new items |
| Extra memory | O(n + m): a whole new list | Only room for the new items, because the same list grows |
| Changes the original object? | No | Yes, for lists |
The difference really shows up inside a loop. We built a list of 20,000 numbers both ways:
import timeit
def with_plus(n):
items = []
for i in range(n):
items = items + [i] # copies the whole list every time
return items
def with_plus_equals(n):
items = []
for i in range(n):
items += [i] # adds to the same list
return items
n = 20_000
print("a = a + b:", round(timeit.timeit(lambda: with_plus(n), number=1), 3), "seconds")
print("a += b: ", round(timeit.timeit(lambda: with_plus_equals(n), number=1), 3), "seconds")
Output on our test machine:
a = a + b: 0.528 seconds
a += b: 0.001 seconds
Using a = a + b in a loop copies the whole list on every pass, so the work grows much faster than the list does. Your exact times will differ, but the gap will be huge either way.
So which should you use? For numbers, pick whichever you find easier to read, because they do the same thing. For lists, prefer += (or .append() and .extend()), especially in loops. Just remember that it changes the original list, so use a = a + b on purpose when you need to leave the original untouched. The += operator is also the standard way to keep a running total in a loop, like total += price. Our guide to loops in Python shows more patterns like this.
One tip for strings: building a long string with += inside a loop can get slow, because each step can create a new string. If you are joining many pieces, collect them in a list and use "".join(pieces) at the end.
Not So Intuitive (but Powerful): += on a List Works With Any Iterable
For lists, += accepts any iterable on the right side, not just another list. An iterable is any Python object that can hand back its items one at a time, like a string, tuple, set, or dictionary. The += operator goes through the iterable and adds each item to the end of the list, just like list.extend():
my_list = [1, 2, 3]
my_list += "Hi" # a string adds each character
print(my_list)
my_list += ("Python", "is", "great") # a tuple adds each item
print(my_list)
my_list += {"First Name": "John", "Last Name": "Doe"} # a dict adds only its keys
print(my_list)
my_list += {"fun"} # a set adds its items (order not guaranteed)
print(my_list)
Output:
[1, 2, 3, 'H', 'i']
[1, 2, 3, 'H', 'i', 'Python', 'is', 'great']
[1, 2, 3, 'H', 'i', 'Python', 'is', 'great', 'First Name', 'Last Name']
[1, 2, 3, 'H', 'i', 'Python', 'is', 'great', 'First Name', 'Last Name', 'fun']
- A string is added one character at a time.
- All the items of the tuple are added to the end of the list.
- Adding a dictionary gives an interesting result: only its keys are added.
- A set's items are added too, but because sets have no fixed order, a set with several items can come out in a different order each time you run the program.
With simple assignment, none of these work. The + operator only joins a list with another list:
my_list = [1, 2, 3]
my_list = my_list + "Hi"
Error:
Traceback (most recent call last):
File "/home/student/aug/main.py", line 2, in <module>
my_list = my_list + "Hi"
~~~~~~~~^~~~~~
TypeError: can only concatenate list (not "str") to list
The reason for this design is that += on a list is really a shortcut for list.extend(), which accepts any iterable. The + operator, on the other hand, builds a new list from two lists, so it insists that both sides are lists.
Here is one more surprising case that shows up in interview questions. A tuple cannot be changed, but a list inside a tuple can:
t = ([1, 2], [3, 4])
try:
t[0] += [99]
except TypeError as e:
print("Error:", e)
print(t)
Output:
Error: 'tuple' object does not support item assignment
([1, 2, 99], [3, 4])
Python raised an error and changed the list anyway. The += first extended the list in place (which worked), then tried to store the result back into the tuple (which failed). Once you know how += works step by step, the output makes sense.
All Assignment Operators in Python
Now that you know how += really works, let's look at the whole family. Assignment operators store or update values in variables. They seem simple, but they quietly control how data changes inside your program, and they show up constantly in exam MCQs and "predict the output" questions.
Every assignment has three parts: the variable on the left, the operator in the middle, and a value or expression on the right. The left side must be something that can hold a value, like a variable name, a list item (scores[0]), or an attribute. With =, Python works out the right side first, then stores the result on the left. With += and the other shortcuts, it reads the current value of the variable, combines it with the right side, and stores the result back. So x += 5 does not mean "add 5 somewhere." It means: take the current value of x, add 5, and store the result back in x.
Here is every assignment operator at a glance:
| Operator | Same as | Example (a = 10, b = 3) | Result |
|---|---|---|---|
= | Assign | a = b | 3 |
+= | a = a + b | a += b | 13 |
-= | a = a - b | a -= b | 7 |
*= | a = a * b | a *= b | 30 |
/= | a = a / b | a /= b | 3.3333333333333335 |
//= | a = a // b | a //= b | 3 |
%= | a = a % b | a %= b | 1 |
**= | a = a ** b | a **= b | 1000 |
&= | a = a & b | a &= b | 2 |
|= | a = a | b | a |= b | 11 |
^= | a = a ^ b | a ^= b | 9 |
<<= | a = a << b | a <<= b | 80 |
>>= | a = a >> b | a >>= b | 1 |
:= | Assign inside an expression | if (n := len(x)) > 3: | n holds the length |
(For numbers, "same as" is exactly right. For lists, remember the in-place difference from the first half of this guide.)
1. Simple Assignment Operator (=)
This is the basic one, also called the primary assignment operator. It stores the value on the right in the variable on the left:
c = 25 # an integer
s = "Hello! CodingZap" # a string
v = 24 < 45 # the result of a comparison (a boolean)
print(c)
print(s)
print(v)
Output:
25
Hello! CodingZap
True
Notice the last one: 24 < 45 is evaluated first, and its result, True, is what gets stored.
2. Multiple and Parallel Assignment
These are not separate operators, just handy ways to use =. Multiple assignment gives several names the same value. Parallel assignment (also called tuple unpacking) gives several names different values in one line:
# Multiple assignment: one value, several names
a = b = c = 45
# Parallel assignment: several values, several names
d, e, f = 100, 200 < 300, "CodingZap"
print("a =", a, ", b =", b, ", c =", c)
print("d =", d, ", e =", e, ", f =", f)
Output:
a = 45 , b = 45 , c = 45
d = 100 , e = True , f = CodingZap
In parallel assignment, values are matched to names in order, and they can be different types. Python evaluates the whole right side before storing anything, which is what makes the classic swap trick work:
x, y = 5, 9
x, y = y, x # swap without a temporary variable
print(x, y)
Output:
9 5
Watch out with multiple assignment and lists. a = b = c = 45 is safe because numbers cannot change. But with a list, every name points to the same list:
a = b = [] # ONE list with two names
a.append("oops")
print(b)
Output:
['oops']
If you want separate lists, create them separately: a, b = [], [].
3. Arithmetic Assignment Operators (+=, -=, *=, /=, //=, %=, **=)
Each of these does the math with the left and right operands, then stores the result in the variable on the left. Only the left variable changes. The right one stays the same:
a, b = 10, 20
a += b # a = a + b
print("a += b ->", a, "| b is still", b)
a, b = 50, 2
a -= b # a = a - b
print("a -= b ->", a)
a, b = 50, 3
a *= b # a = a * b
print("a *= b ->", a)
a, b = 42, 3
a /= b # a = a / b (the result is always a float)
print("a /= b ->", a)
a, b = 41, 3
a //= b # a = a // b (floor division)
print("a //= b ->", a)
a, b = 50, 3
a %= b # a = a % b (the remainder)
print("a %= b ->", a)
a, b = 5, 3
a **= b # a = a ** b (a to the power of b)
print("a **= b ->", a)
Output:
a += b -> 30 | b is still 20
a -= b -> 48
a *= b -> 150
a /= b -> 14.0
a //= b -> 13
a %= b -> 2
a **= b -> 125
+=(addition):abecame 30, butbis still 20. The sum is stored only ina.-=(subtraction): subtracts the right operand from the left.*=(multiplication): multiplies the left operand by the right./=(division): always gives afloat, even when the division is exact. 42 / 3 gives 14.0, not 14. Our guide to Python data types explains how Python picks the type of a result.//=(floor division): divides and rounds down to the nearest whole number. 41 // 3 gives 13.%=(modulus): stores the remainder. 50 % 3 gives 2.**=(exponent): raises the left operand to the power of the right. 5 ** 3 gives 125.
One exam favorite: with negative numbers, //= rounds down (toward negative infinity), not toward zero, and %= follows along:
a = -7
a //= 2 # rounds DOWN, toward negative infinity
print(a)
b = -7
b %= 2 # the remainder takes the sign of the divisor
print(b)
Output:
-4
1
4. Bitwise Assignment Operators (&=, |=, ^=, <<=, >>=)
These work on the binary (bit) form of integers, a topic you usually meet in computer organization classes. They do the bitwise operation and store the result on the left:
a = 50 # 110010 in binary
b = 3 # 000011 in binary
x = a
x &= b # AND
print("a &= b ->", x)
x = a
x |= b # OR
print("a |= b ->", x)
x = a
x ^= b # XOR
print("a ^= b ->", x)
x = a
x <<= 1 # shift left (same as * 2)
print("a <<= 1 ->", x)
x = a
x >>= 1 # shift right (same as // 2)
print("a >>= 1 ->", x)
Output:
a &= b -> 2
a |= b -> 51
a ^= b -> 49
a <<= 1 -> 100
a >>= 1 -> 25
50 is 110010 in binary and 3 is 000011. The only bit they share is the 2s bit, so 50 & 3 is 2. Shifting left by 1 doubles the number, and shifting right by 1 halves it (rounding down).
The same |= operator has an everyday use with sets, where it adds items in place:
tags = {"python", "loops"}
tags |= {"lists"} # sets use |= to add items in place
print(sorted(tags))
Output:
['lists', 'loops', 'python']
5. The Walrus Operator (:=)
Added in Python 3.8, the walrus operator assigns a value inside an expression, so you can store and test a value in one step:
scores = [88, 92, 75, 64]
if (count := len(scores)) > 3:
print("You entered", count, "scores")
Output:
You entered 4 scores
Here, len(scores) is stored in count and compared with 3 in the same line. The parentheses matter here. Without them, count would store the result of len(scores) > 3, which is True, instead of 4.
Assignment (=) vs Comparison (==)
Mixing up = and == causes a lot of pain in exams, because they look so similar. They do completely different jobs:
| Criteria | Assignment (=, +=, ...) | Comparison (==, !=, <, ...) |
|---|---|---|
| Purpose | Store or update a value | Check a condition |
| What it gives back | Nothing. It is a statement. (Only := gives back a value.) | True or False |
| Changes a variable? | Yes | No |
| Where it is used | On its own line | In if, while, and other conditions |
| Symbol | One = | Two == |
If you use = by mistake in an if, Python stops you right away:
x = 5
if x = 5:
print("five")
Error:
File "/home/student/aug/main.py", line 2
if x = 5:
^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
Programming Task: Assignment Operators With Python Lists
This task comes up often in theory and lab exams: add the elements of one list to another list using an assignment operator, then print the updated list.
list1 = [1, 2, 3] # original list
list2 = [4, 5] # second list
list1 += list2 # performing addition assignment
print(list1) # list1 itself has changed
Output:
[1, 2, 3, 4, 5]
list1starts as[1, 2, 3]. When we use+=with lists, Python adds the elements oflist2directly intolist1.- The original
list1is modified, and no new list is created.
Exams often push this one step further. Try to predict the output before you read it:
a = [1, 2]
b = a
a += [3]
a = a + [4]
print(a)
print(b)
Output:
[1, 2, 3, 4]
[1, 2, 3]
b = a makes both names point to the same list. a += [3] changes that shared list, so b sees the 3. Then a = a + [4] creates a new list and points only a at it, so b never sees the 4. Many students assume += behaves the same for every data type, and this question is designed to catch exactly that.
Common Pitfalls With Assignment Operators and How to Avoid Them
1. Changing a shared list by accident. If two names point to the same list (through b = a, a = b = [], or passing the list into a function), += changes it for all of them. If you need an independent copy, make one first with a.copy() or list(a).
2. Using += on a global variable inside a function.
count = 0
def add_one():
count += 1 # Python treats count as a local variable here
add_one()
Error:
Traceback (most recent call last):
File "/home/student/aug/main.py", line 6, in <module>
add_one()
~~~~~~~^^
File "/home/student/aug/main.py", line 4, in add_one
count += 1 # Python treats count as a local variable here
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
Because the function assigns to count, Python treats count as a local variable, one that does not have a value yet. If you really need to change the variable outside the function, declare it with global:
count = 0
def add_one():
global count # tell Python to use the variable outside the function
count += 1
add_one()
add_one()
print(count)
Output:
2
A cleaner habit is to pass the value in as an argument and return the new value.
3. Using a mutable default argument.
def add_item(item, basket=[]): # the default list is created only once
basket += [item]
return basket
print(add_item("apple"))
print(add_item("bread")) # still holds "apple" from the first call
Output:
['apple']
['apple', 'bread']
The default list is created only once, when the function is defined. Every call that uses the default shares that same list, and += keeps adding to it. The fix is to use None as the default and create a new list inside the function:
def add_item(item, basket=None):
if basket is None:
basket = [] # a fresh list on every call
basket += [item]
return basket
print(add_item("apple"))
print(add_item("bread"))
Output:
['apple']
['bread']
4. Reusing one variable name for different things. Use clear, descriptive names like total_price instead of reusing x for everything. It makes accidental overwrites much easier to spot.
Many beginner mistakes with assignment operators turn into bugs or wrong output later. Our guide to common Python errors students make, including the UnboundLocalError above, can help you spot these issues early.
Conclusion
In this article, we looked at the difference between the simple assignment a = a + b and the augmented assignment a += b. We showed with real code that augmented assignment changes a list in place, while simple assignment builds a new list. We also saw that this difference disappears for immutable types like integers, strings, and tuples, and that += on a list can accept any iterable. Finally, we went through every assignment operator in Python and the traps that cost students marks.
Takeaways:
- For numbers, strings, and tuples,
a += banda = a + bgive the same result. - For lists,
a += bchanges the original list, and every name that points to it sees the change. - For lists,
a = a + bbuilds a new list every time, which is slower for big lists, especially inside loops. - An assignment always updates the variable on the left. With
=, the right side is worked out first. /=always produces a float, and//=rounds down, even for negative numbers.- Use
==to compare and=to assign. Only the walrus operator:=can assign inside a condition.
Frequently Asked Questions
1. Is a += b the same as a = a + b in Python?
For numbers, strings, and tuples, yes: both give the same result, and the original value is never changed. For lists, no. a += b changes the original list in place, while a = a + b creates a new list and points a at it. Any other variable pointing to the original list will only see the change made by +=.
2. Is a += b faster than a = a + b?
For lists, yes. a += b only adds the new items, while a = a + b copies every item into a brand-new list. Inside a loop, the difference can be huge. For numbers, there is no meaningful difference.
3. Does += create a new list in Python?
No. On a list, += works like list.extend(): it adds the items to the same list, and the list keeps its ID. On immutable types like int, str, and tuple, += points the variable at a different object, because the original cannot change.
4. Do assignment operators always change the original variable in Python?
They always update the variable on the left. For numbers and strings, Python stores a new object in that variable. For mutable objects, in-place operators change the existing object itself: += on a list, and |= on a set or dictionary (Python 3.9 and later), which is why other variables pointing to it can see unexpected changes.
5. Can assignment operators be used inside conditional statements?
The regular ones cannot. Writing if x = 5: is a SyntaxError, and Python even suggests == or :=. Since Python 3.8, the walrus operator := lets you assign inside a condition, like if (n := len(items)) > 3:.
6. Why do I get UnboundLocalError when I use += inside a function?
Because assigning to a variable anywhere inside a function makes it local to that function. count += 1 tries to read the local count before it has a value. Declare it with global count, or better, pass the value in as an argument and return the new value.
7. What does the := operator do in Python?
It is the walrus operator, added in Python 3.8. It assigns a value and gives that value back in the same expression, so you can store and test a value at once, for example inside an if or while condition.


