Example:
def exampol(x, y):
for i in x:
x[i] = x[i]*x[i]
for j in range(0, len(y)):
y[j] = y[j]*y[j]
return x, y
x = [0,1,2,3,4]
y = [0,10,20,30,40,50,60]
exampol(x, y)
print(x)
print(y)
After calling the function exampol()
the output is:
x = [0, 1, 4, 9, 16]
y = [0, 100, 400, 900, 1600, 2500, 3600]
I don't understand why this happens. As far as I know, variables in a function are local in scope and parameters passed to the function should not be changed from their original value.
Why are the original variables passed as arguments to the function modified?
They are two different concepts, one thing is the name or identifier (what we call "variable") and another is the object to which it is associated. Your list is not defined inside the function, you pass it as an argument.
In Python , a variable is really just a name, an identifier, that is associated with the reference of an object in memory and that is used to access it. The same object can have several names associated with it:
If we do:
a
andb
they are names that are both associated to the same objectlist
in memory , we can make thema
be associated to another object by reassigning:We can use
a
or any other name associated with the object to access it, its methods and attributes:A variable defined inside a function only exists inside that function as you comment, also any reassignment attempt to a global variable inside the function causes the creation of a local variable of the same name leaving the global one intact (as long as we don't use
global
ornonlocal
). We can say that global identifiers inside a function are by default read-only, this is because the interpreter first looks for the variable in the namespace local to the function, if it doesn't find it it looks in the global one.Now, any attempt to change the object that a global variable is attached to within a function automatically creates a local variable of the same name. When I say "change the object it's associated with" I don't mean modifying the properties of the object itself, I mean making the variable point to another object, an assignment:
Function/method arguments in Python are passed by assignment, by "object reference" (you don't pass the value or a copy of the object, you just pass a reference to an object in memory).
In addition to passing by object reference, it is important to take into account the concept of object mutability (*see list at the end of the answer). Lists are mutable objects , this implies that the lists you modify inside the function are the same objects as the ones you pass to it as an argument:
If the object is immutable, such as an integer, float, or string, this doesn't happen, because "modifying" an immutable object via a variable actually always means creating a new object and assigning the new reference to the variable. Therefore, when we do something like inside the function
x += 1
, beingx
an integer passed as an argument, the namex
becomes associated with a new object in memory, since the sequence is to add one to x, store it in a new object integer and associate (assign) it to the namex
:Departure:
Since a list is a mutable object, modifying its values within the function does not create a new object, but rather it is modified directly:
Departure:
If you don't want this to happen, you must either pass a copy of the list to the function or create the copy within the function itself:
In this case a copy is created by slicing, you can also use
copy.copy()
. If your list only contains integers (immutable) this is enough. If your list had mutable elements, like lists or dictionaries, the above just creates a copy of the list, but its elements remain the same as the original list (same references) so you must usecopy.deepcopy()
so that the elements it contains are also copied.Python objects according to their mutability:
To complete the answer, taking into account @fedorqui's comment, I leave a classification of objects in standard Python according to their mutability:
Mutable:
bytearray
dict
list
set
Immutable:
bool
bytes
complex
decimal
int
float
frozenset
str
/unicode
tuple
range
In addition to the above, in the standard library we have the module
collections
that provides alternatives to the prebuilt containers and that are normally wrappers or based on the previous ones (and therefore having the same immutability property or not as these).