Have you ever faced a bug in your code when writing Python where you thought you were modifying a local variable but actually modified the variable outside of the function too?
For example, if you have a function like this:
def add_one(x: int, y: list) -> None:
And when you then call it
a = 0
You find that
In this article we’ll explore what causes this behaviour so that you can avoid running into odd bugs in your code.
The first step in understanding this behaviour is to learn about the difference in how mutable and immutable types behave during assignment.
In Python we have both mutable and immutable data types, which means that you can modify the values of some data types, whilst you cannot modify the values of others.
Examples of mutable types are
And examples of immutable types are
Having mutable data types means that we can modify them and still have the same object, whilst if we try to modify an immutable type we create a new object, To be able to demonstrate this behind the scenes we’ll use the built in
We can see this in action by comparing a mutable data type (list), to an immutable one (int):
x = 0
What we can see here is that after adding 1 to
a = 00 list is still referencing the same object.
And so we can see that if we try to modify an immutable data type, we actually reference a new object, whereas for a mutable one we keep the reference to the same object and instead directly modify the contents of the object.Passing By Assignment
Now that we’ve seen the difference in how mutable and immutable objects work when you apply operations on them, let’s understand the other part of the puzzle that determines why we can modify mutable objects within a function like we saw previously.
This behaviour is due to how Python handles passing arguments to functions, which is done through a principle called “passing by assignment”. Passing by assignment means that we pass in variables in the same way that we would handle variable assignment, for example:
a = 1
What’s happened here is that we’ve assigned a to reference to integer object 1, and then we’ve assigned b to be equal to
a = 01. In Python terms that means that
a = 02 is now referencing the same object as
a = 01. The check afterwards,
a = 04, checks if both components on either side of our conditional are referencing the same object, and returns True if they do, otherwise it returns False.
If we then modify
a = 01 by adding 1 to it, since we know from before that integers are immutable, a is now referencing a new object, whilst
a = 02 still references the old object, and hence they are no longer referencing the same object.
Knowing now how assignment works, if we look back at our list example:
x = 
We have the sample principle here, with
a = 00 referencing the same object. However, since list is a mutable object, modifying it doesn’t lead to creating and referencing a new object, instead we keep the same object reference and just modify the contents of the object.Bringing It All Together
Now that we understand how mutable and immutable objects differ, and also how assignment works in Python, let’s understand what’s actually happening when we call our add_one function from above.
To avoid having to scroll a lot, let’s copy our toy example here again once more
def add_one(x: int, y: list) -> None:
After creating the function, the first thing we do is assign a to reference the integer object 0, and b an empty list object.
Next we call the function with
a = 01 and
a = 02, this now means that
a = 01, and
a = 00 gets assigned the value of
a = 02. From our previous section we now know that this means that
a = 01, and
a = 00 is referencing the value contained in
a = 02.
Now inside the function we modify
Next we add the element 1 to the end of our list. In this case, since our list is mutable, we don’t create a new object but instead update the existing one.
Now that we’ve reached the end of the function and we leave its scope,
a = 00 cease to exist since they are variables local to the scope of the
a = 13 function. Our value a never got updated, because the object it’s referencing never changed (since it is immutable). On the other hand, our value
a = 02 did get changed because the object that it is referencing got changed.Summary
Python’s internals are very powerful and allow for very flexible code. however, sometimes we can be caught off-guard by their behaviour if we don’t fully understand what’s happening behind the scenes. This can lead to weird bugs in your program that can feel very hard to track down.
Understanding how Python’s assignment operation works, and how mutable and immutable data types behave differently under modification means you don’t just avoid mistakenly having these sorts of “bugs” in your programs, but you can actually use these behaviours to your advantage to writer cleaner, more concise, Python code
Can you change a function in Python?
Most Python objects can be changed after they've been created. Lists, sets, and dictionaries can all be changed, whereas tuples, numbers, and strings cannot. Objects that can be changed are called mutable and the act of changing one of these objects is a mutation.
How do you redefine a function in Python?
Python function redefinition It is possible to redefine an already defined function. #!/usr/bin/python # redefinition.py from time import gmtime, strftime def show_message(msg): print(msg) show_message("Ready.") def show_message(msg): print(strftime("%H:%M:%S", gmtime())) print(msg) show_message("Processing.")
What is a modifying function?
The MODIFY function allows an application program to change several of the processing characteristics associated with it and with the terminal. For example, the MODIFY function could be used by an application to change the definition of its terminal from upper-case to lower-case.
Can you modify parameters in Python?
The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all, i.e. they are immutable. It's different, if we pass mutable arguments. They are also passed by object reference, but they can be changed in place within the function.