canyon289
canyon289

Reputation: 3495

Why does not the + operator change a list while .append() does?

I'm working through Udacity and Dave Evans introduced an exercise about list properties

list1 = [1,2,3,4]
list2 = [1,2,3,4]

list1=list1+[6]
print(list1)
list2.append(6)
print(list2)

list1 = [1,2,3,4]
list2 = [1,2,3,4]

def proc(mylist):
    mylist = mylist + [6]

def proc2(mylist):
    mylist.append(6)

# Can you explain the results given by the four print statements below? Remove
# the hashes # and run the code to check.

print (list1)
proc(list1)
print (list1)

print (list2)
proc2(list2)
print (list2)

The output is

[1, 2, 3, 4, 6]
[1, 2, 3, 4, 6]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4, 6]

So in a function the adding a 6 to the set doesn't show but it does when not in a function?

Upvotes: 10

Views: 4267

Answers (6)

brandizzi
brandizzi

Reputation: 27050

When you execute mylist = mylist + [6], you're actually creating an entirely new list and assigning it to the local variable mylist. This local variable mylist will disappear after the function completes, and the newly created list will also vanish.

On the other hand, when you execute mylist.append(6), you don't create a new list. Instead, you modify the existing list that mylist is pointing to by adding a new element to it. This change is reflected in the original list (which list2 also points to). The mylist variable will still disappear after the function ends, but in this case, the original list remains altered.

Let's break this down visually:


What Happens When You Call proc()

When you write list1 = [1, 2, 3, 4, 5], you're creating a new list object (on the right side of the equals sign) and assigning it to a new variable, list1, which points to this object.

Creating new list instance and global variable

When you call proc(), a new variable mylist is created. Since you pass list1 as a parameter, mylist points to the same object:

Calling method creates local variable

However, the operation mylist + [6] creates a new list object that combines the elements of the object pointed to by mylist with [6]. Since this new list is assigned to mylist, the situation changes, and mylist no longer points to the same object as list1:

mylist points to new list object

Remember, mylist is a local variable that will disappear after proc() ends. So, when the function execution is complete, mylist is gone:

mylist is gone

Since no other variable points to the object created by mylist + [6], it will disappear too (collected by the garbage collector):

GC collects the list

Notice that in the end, the object pointed to by list1 is not changed.


What Happens When You Call proc2()

The scenario changes when you call proc2(). Initially, it's the same: you create a list...

Creating new list instance and global variable

...and pass it as a parameter to a function, which generates a local variable:

Calling method creates local variable

However, instead of using the + operator (which generates a new list), you use the append() method. The append() method does not create a new object; it modifies the existing one:

Appending a value to a list

After the function ends, the local variable will disappear, but the original list pointed to by both mylist and list1 remains altered:

It is still altered

Since list1 still points to this list, the original list is not destroyed.


EDIT: If you want to see all of this in action, check out this amazing simulator:

enter image description here

* If you're unfamiliar with garbage collection, you'll soon understand it better after grasping this concept.

Upvotes: 19

Owen
Owen

Reputation: 931

As well as the comprehensive answers already given, it's also worth being aware that if you want the same looking syntax as:

mylist = mylist + [6]

...but still want the list to be updated "in place", you can do:

mylist += [6]

Which, while it looks like it would do the same thing as the first version, is actually the same as:

mylist.extend([6])

(Note that extend takes the contents of an iterable and adds them one by one, whereas append takes whatever it is given and adds that as a single item. See append vs. extend for a full explanation.)

Upvotes: 2

user907629
user907629

Reputation: 534

In the third line, you did this

list1=list1+[6]

So, when you did the below after the above line,

print (list1)

which printed list1 that you created at the start and proc procedure which adds list1 + [6] which is creating a new list inside the function proc. Where as when you are appending [6], you are not creating a new list rather you are appending a list item to already existing list.

But, keep in mind. In line 7, you again created the list

list1 = [1,2,3,4]

Now you wanted to print the list1 by calling it explicitly, which will print out the list1 that you reinitialized again but not the previous one.

Upvotes: 0

kindall
kindall

Reputation: 184091

This, in one form or another, is a very common question. I took a whack at explaining Python parameter passing myself a couple days ago. Basically, one of these creates a new list and the other modifies the existing one. In the latter case, all variables that refer to the list "see" the change because it's still the same object.

Upvotes: 0

Levon
Levon

Reputation: 143047

Ordinarily, in the first case in function proc you would only be able to change the global list by assignment if you declared

global mylist

first and did not pass mylist as a parameter. However, in this case you'd get an error message that mylist is global and local: name 'mylist' is local and global. What happens in proc is that a local list is created when the assignment takes place. Since local variables go away when the function ends, the effect of any changes to the local list doesn't propagate to the rest of the program when it is printed out subsequently.

But in the second function proc2 you are modifying the list by appending rather than assigning to it, so the global keyword is not required and changes to the list show elsewhere.

Upvotes: 2

happydave
happydave

Reputation: 7187

Variables in python can always be thought of as references. When you call a function with an argument, you are passing in a reference to the actual data.

When you use the assignment operator (=), you're assigning that name to refer to an entirely new object. So, mylist = mylist + [6] creates a new list containing the old contents of mylist, as well as 6, and assigns the variable mylist to refer to the new list. list1 is still pointing to the old list, so nothing changes.

On the other hand, when you use .append, that is actually appending an element to the list that the variable refers to - it is not assigning anything new to the variable. So your second function modifies the list that list2 refers to.

Upvotes: 3

Related Questions