Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happen to a list when passed to a function?

I'm trying to understand how a list is treated when passed as an argument to a function. So what I did was the following:

I initialized a list:

ll = [1,2,3,4] 

and define a function:

def Foo(ar):
    ar += [11]

I passed the list to the function:

Foo(ll)

and when I print it I got:

print ll # [1, 2, 3, 4, 11] #case(1)

So far so good.

Now I modified the function in order to reset the list such that it has a single element only:

def Foo(ar):
    ar = [11]

I recalled the syntax:

Foo(ll)

and when I reprint it, it resulted in the same list:

print ll # [1, 2, 3, 4] # case(2)

I thought the list was passed as reference; so whatever we do to the list inside a function will always change the original function passed from the main program. So for case(2) I was expecting the following result:

print ll # [11] # case(2) expected result

Am I missing something here?

like image 775
rnels12 Avatar asked Dec 08 '22 02:12

rnels12


2 Answers

You have to make the difference between the object and the name of the object. Lists in Python are mutable objects, so they can be changed whenever you have a reference to it.

Names are just references to objects. Remember that technically in Python there are not variable, just names and objects, and objects are bound to names.

So, with that in mind, let's see your code:

def Foo1(ar):
    ar += [11]

This function takes a list, binds it to the local name ar and then modifies the list, adding a new value.

However this other code:

def Foo2(ar):
    ar = [11]

This function takes a list, bound to the ar name, and then rebinds the name ar to a new list with one value. The original object is unmodified and fogotten, inside this function.

Then when you do:

a = [1,2,3]

And then call:

Foo1(a)

that modifies the list adding a new value, but:

Foo2(a)

does nothing to the value of a.

If you want to write a function that replaces all the content of the list with another, you can do that with:

def Foo3(a):
    a[:] = [11]

This code does not rebind a but modifies the list by replacing the content with the new list.

To further illustrate my point, look at this example:

a = []
b = []
c = a
a.append(1)
b.append(2)
c.append(3)
print a
print b
print c

It will print:

[1, 3]
[2]
[1, 3]

Can you to tell why?

like image 21
rodrigo Avatar answered Dec 10 '22 16:12

rodrigo


ar += [11] is not just an assignment. It's a method call (the method called is: __iadd__). when Python executes that line it calls the method and then assigns ar to the result. The __iadd__ method of list modifies the current list.

ar = [11] is an assignment and hence it simply changes the value of the local name ar. But there is no link between the ar name inside the function and the value of the ll variable.

You probably want something like:

ar[:] = [11]
like image 179
Bakuriu Avatar answered Dec 10 '22 15:12

Bakuriu