0

Once I define a list in main() and passed it as a function parameter, I expected that its content will remain the same once we exit the function. I have the following code snippet:

def test(a): 
    a.append(1000) 
    return a 

def main(): 
    a = [1,2,3] 
    print(a, test(a))
    
main()

Output is clear.

# Output: [1,2,3,1000] [1,2,3,1000] 

Even though the initial list contains 3 elements, function test() seems to modify its content. This thing does not happen to variables:

def test(a): 
    a = a + 10
    return a 

def main(): 
    a = 5
    print(a, test(a))
    
main()

# Output: 5 15 

Why is that? Why does Python modify the initial lists and not variables?

Bianca I.
  • 31
  • 2

2 Answers2

1
a.append()

mutates the a which was passed by reference

a = a + 10

assigns a value to a new local variable in the function called a

Integers are immutable, but if there were some method that could be called on that a (on the right hand side) to mutate it, it would also be reflected in the caller.

OregonTrail
  • 8,594
  • 7
  • 43
  • 58
0

Some objects in python (like lists, dicts and sets) are mutable, whereas others (like tuples, frozensets, strings and numbers) are immutable.

Operations on mutable objects modify the object themselves. Many immutable objects also allow operations, which in this case return a new object. (Internally this is implemented with the dunder "magic methods", which in this case just return a new object. x OPERATOR y actually calls a method on x(and/or y).)

Since in python x = y binds the name x to point to y, if y is mutable and you modify it, x will point to the modified y. But if y is immutable (but allows operations), operations on y will create a new y, to which x no longer points:

x = [] # mutable
y = x # y and x both point to a particular '[]'
x += ["hi"]
y == ["hi"] # True

x = 0
y = x # y and x both point to 0
x += 7 # x now points to 7
y == 7 # False 

Exactly the same thing goes on when you parse an argument to a function---you bind a name in the function's scope pointing to that object. What then happens to the object pointed to by the name depends upon the type of object and what you do to it. If it's mutable and you mutate the object pointed to by the name in the function, you will mutate the object itself, and any other names bound to that object ouside the function will see the changed object.

This is the reason that we don't generally do this:

def f(x=[]):
    ...

Since f is evaluated once, when the module is first loaded, x will point to the same list for the duration of the function. Thus if the function does anything to x, x will be in that state next time it's called (which is rarely what you want).

2e0byo
  • 5,305
  • 1
  • 6
  • 26
  • Note that I am *sure* there is a canonical for this question, but I couldn't find it. If someone does could we close this Q as a dupe and I'll delete this answer? – 2e0byo Jul 23 '22 at 09:53