0

Why it gives different outputs:

is there a difference between + and +=

def func1(lst1, lst2):
    lst1 += lst2

lst1 = [1, 2, 3]
lst2 = ["a", "b"]
func1(lst1, lst2)
print(lst1)

and

def func1(lst1, lst2):
    lst1 = lst1 + lst2
    
lst1 = [1, 2, 3]
lst2 = ["a", "b"]
func1(lst1, lst2)
print(lst1)

Thanks in advance

Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
  • 1
    first program gives: [1,2,3] Second one : [1,2,3,'a','b','c'] – Mahmud Hassan Jul 22 '21 at 15:32
  • 1
    Does this answer your question? [What exactly does += do in python?](https://stackoverflow.com/questions/4841436/what-exactly-does-do-in-python) – PCM Jul 22 '21 at 15:32
  • 1
    @NirAlfasi Running in 3.8 I get two different outputs as well. Honest question, if those two operators are the same and it's just syntactic sugar (which was my assumption) why would we get two different responses from the `print()` of `lst1`? – JNevill Jul 22 '21 at 15:33
  • 5
    Does this answer your question? [Why does += behave unexpectedly on lists?](https://stackoverflow.com/questions/2347265/why-does-behave-unexpectedly-on-lists) – s_pike Jul 22 '21 at 15:34
  • `+` and `+=` are two completely independent operators. For mutable built-ins like list `+=` has **always** been a mutation, where `x = x + y` is always a rebinding. – user2390182 Jul 22 '21 at 15:36
  • @NirAlfasi This one threw me for a loop. My assumption was that it was syntactic sugar, but it looks like `+` operator creates a new version where `+=` modifies the original reference. That's strange as hell. – JNevill Jul 22 '21 at 15:37
  • 1
    @NirAlfasi I removed that part, my bad. – user2390182 Jul 22 '21 at 15:38
  • 1
    That linked answer by `s_pike` mentions it's the difference between `__add__` and `__iadd__`. Learn something new every day on here. – JNevill Jul 22 '21 at 15:39
  • @JNevill I was too hasty and I was wrong, my bad, comment removed~ – Nir Alfasi Jul 22 '21 at 15:40
  • I'm actually not sure about that answer anymore - I think the answer given by @Thomas Weller below is correct. – s_pike Jul 22 '21 at 15:44
  • `x += y` is syntactic sugar, but *not* for `x = x + y`; it's syntactic sugar for `x = x.__iadd__(y)` The assignment back to `x` is only significant if `x.__iadd__` does not mutate `x` (or perhaps when `x.__iadd__` does not actually exist and Python alls back to `x.__add__`). If `x` gets rebound to the same object, then you can't really tell that the rebinding occurred. – chepner Jul 22 '21 at 16:19

3 Answers3

10

The difference here is that += changes the initial list lst1. Whilst the lst1 = lst1 + lst2 creates a new list and rewrites local reference lst1 which does not affect global object lst1. If you try printing lst1 inside the functions, both cases would give you the same result.

Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
3

In your first example, you are passing a reference to lst1. Therefore, the increment affects the list that lst1 refers to.

In your second example, you're also passing a reference but the operation lst1 + lst2 creates a new list instance and lst1 subsequently points at that. Thus your original list is unaffected.

You need to decide if you really want lst1 modified or whether you want to know what the addition of the two lists looks like

3

A good IDE will give you a hint, like so:

Pycharm

If you recognize the dark grey color of lst1, move your mouse over it and it will give you a hint. Here, the problem is that the local variable is not used, as explained by @Yevhen Kuzmovych.

+= can have a different implementation than +. That's the case for lists: += modifies the list inplace whereas + gives you a new list and using the same name on the left side makes that not so obvious.

It also says that you have a naming issue, called shadowing. Did you expect lst1 from the outer scope to update, because it has the same name? If you thought that, you need to read about scope. If you know another programming language, you also want to understand the difference between pass by value, pass by reference and pass by assignment (Python).

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222