If you’ve ever modified a variable inside a Python function and been surprised or confused by what happened to it outside the function, you’re not alone. This bothered me for a long time.
Coming from tutorials that talk about “call by value” and “call by reference”, I assumed that Python should follow one of these two models. It doesn’t happen. Python does something different, and once you understand it, a lot of previously confusing behavior will suddenly click.
In this article, you will learn:
What is the meaning of calling by price and calling by reference?
How do other languages like C handle this?
What Python actually does (passing object references)
How mutable and immutable types affect behavior within functions.
Table of Contents
Defined as a call by price and a call by reference.
Before we get to Python, let’s quickly define these two terms.
Call for pricing. This means that a copy of the variable is passed to the function. Whatever you do with it inside the function, nothing actually changes.
Call for reference. This means that the original memory space of the variable is passed. Changes inside the function directly affect the original variable.
Many languages support one or both of these models. Python, however, uses neither – at least not in the traditional sense.
How it works in C (with examples)
C is a good example of a language that explicitly supports both models.
Here’s how you call by value in C. The actual variable is unaffected:
#include
void modify(int *n) {
*n = *n + 10;
printf("Inside function: %d\n", *n); }
int main() {
int x = 5;
modify(&x);
printf("Outside function: %d\n", x);
return 0; }
Output:
Internal function: 15
Outside event: 15 ← The original was changed!
In C, you choose behavior by explicitly deciding whether to pass a pointer or a simple value. Python doesn’t give you that choice, but what it does instead is actually quite logical.
What does Python do instead?
Python uses a model called Passing object references (sometimes called passing through assignments).
When you pass a variable to a function in Python, you are referring to the object that the variable points to, not a copy of the value, not the variable itself.
What happens next depends on whether that object is. changeable (can be substituted in place) or Immutable (Cannot be changed in place).
Mutable vs Immutable Types
Immutable types Python includes int, float, strand tuple. These items cannot be exchanged on site. When you “replace” one inside a function, Python creates an entirely new object and the original is left untouched.
def modify_number(n):
n = n + 10
print("Inside function:", n)
x = 5
modify_number(x)
print("Outside function:", x)
Output:
Internal function: 15
External function: 15 ← original unchanged
Variable types Included list, dictand set. These may change from place to place. When you modify a function inside a function, you are modifying the same object that the caller has a reference to.
def modify_list(items):
items.append(99)
print("Inside function:", items)
my_list = (1, 2, 3)
modify_list(my_list)
print("Outside function:", my_list)
Output:
Inner function: (1, 2, 3, 99)
External function: (1, 2, 3, 99) ← Change original!
Here’s the key insight: Python doesn’t decide behavior based on how you pass an object, it decides based on what you’re passing it.
The result
Python does not use call by value or call by reference. This Passes a reference to the object.where the function receives a reference to the object, and whether the object can be modified in place determines what happens next.
To retrieve:
Immutable types (
int,str,tuple): a new object is created inside the function, the original remains the same.Variable types (
list,dict,set): the original object is modified directly.
Once it clicked for me, many “Why is Python doing this?” Moments began to make sense. If you’re just getting started with functions in Python, keep this in mind, it will save you a lot of debugging headaches.