1. Difference Between Passing by Value and Passing by Reference
In Python, there are two ways to pass arguments to functions: pass-by-value and pass-by-reference.- Pass-by-value: A method where a copy of the value is passed to the function as an argument; modifying the parameter inside the function does not affect the original variable.
- Pass-by-reference: A method where a reference (address) to the variable is passed to the function, so changes made inside the function are reflected in the original variable.
2. Characteristics of Objects in Python
In Python, all data are treated as objects, and based on their object characteristics they are classified as either immutable (cannot be changed) or mutable (can be changed). This distinction affects how they behave when passed as arguments to functions.- Immutable objects: objects that cannot be modified after creation. Examples include integers (
int
), floating-point numbers (float
), strings (str
), tuples (tuple
). Because these data types cannot be changed once created, operations on them inside a function do not affect the caller even when passed by reference. - Mutable objects: objects that can be modified after creation. Examples include lists (
list
), dictionaries (dict
), sets (set
). Because changes to these data types within a function are reflected in the caller, they are especially affected by Python’s reference-passing behavior.

3. How Python Passes Arguments
In Python, when you pass arguments to a function, references to objects are passed. This behavior is sometimes called “pass-by-object-reference.” From here, we’ll walk through concrete examples that illustrate Python’s behavior depending on whether objects are immutable or mutable.3.1 Immutable Objects
When you pass an immutable object to a function, assigning a new value inside the function creates a new object and does not affect the original object.Example: Passing an Immutable Integer
def modify_number(num):
num = num * 2
print("Number inside the function:", num)
original_num = 5
modify_number(original_num)
print("Number outside the function:", original_num)
Output:Number inside the function: 10
Number outside the function: 5
ExplanationInside the modify_number function, the variable num is doubled, but this does not affect original_num outside the function. Since integers are immutable, a new object is created when a new value is assigned, and original_num remains unchanged.
3.2 Mutable Objects
On the other hand, when a mutable object is passed to a function, its reference is also used inside the function. As a result, changes made within the function are reflected in the original object as well.
Example: Passing a Mutable List
def add_item(my_list):
my_list.append("Added element")
print("List inside the function:", my_list)
original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)
Output:List inside the function: ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2', 'Added element']
ExplanationSince lists are mutable, the changes made inside the add_item function are directly reflected in original_list outside the function. In this way, mutable objects are shared between inside and outside the function, so modifications within the function also affect the caller.
4. Cautions and Countermeasures for Passing by Reference
Passing mutable objects to functions in Python can lead to unexpected behavior. Here are some countermeasures to avoid such issues.4.1 Use Copies of Objects
If you want to modify an object inside a function, you can avoid affecting the original by copying it before making changes. In Python, you can use thecopy
module to create shallow copies (copy.copy
) or deep copies (copy.deepcopy
).Example: Using Deep Copy to Avoid Mutable Object Issues
import copy
def add_item(my_list):
my_list_copy = copy.deepcopy(my_list)
my_list_copy.append("Added element")
print("List inside the function (copy):", my_list_copy)
original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)
Output:List inside the function (copy): ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2']
Explanation By using deepcopy
, a new object is created inside the function, leaving the original list unaffected. This allows independent changes inside and outside the function.4.2 Use None
for Default Arguments
Avoid setting mutable objects as function default arguments; it’s recommended to use None
as the default and create a new object inside the function.Example: Safe Way to Make the Default Argument None
def add_item(my_list=None):
if my_list is None:
my_list = []
my_list.append("New element")
print("List inside the function:", my_list)
return my_list
# When no list is passed
result = add_item()
print("Returned list:", result)
# When a list is passed
existing_list = ["Element 1", "Element 2"]
result = add_item(existing_list)
print("Returned list:", result)
print("Original list:", existing_list)
Output:List inside the function: ['New element']
Returned list: ['New element']
List inside the function: ['Element 1', 'Element 2', 'New element']
Returned list: ['Element 1', 'Element 2', 'New element']
Original list: ['Element 1', 'Element 2', 'New element']
Explanation By using the default argument None
and generating a new list inside the function, you can prevent external lists from being unexpectedly modified. Setting None
as the default argument makes clear whether to create a new list or use the one provided.
5. Practical Example: Code to Deepen Understanding of Pass-by-Reference
Let’s review what we’ve covered with a practical example.Example: Modifying a Dictionary’s Keys and Values
Dictionaries are mutable objects, so operations performed inside a function affect the dictionary outside the function. The example below shows the behavior when changing a dictionary’s keys and values.def modify_dict(my_dict):
my_dict["new key"] = "new value"
print("Dictionary inside the function:", my_dict)
original_dict = {"key1": "value1", "key2": "value2"}
modify_dict(original_dict)
print("Dictionary outside the function:", original_dict)
Output:Dictionary inside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}
Dictionary outside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}
Explanation Because dictionaries are mutable, additions made inside the function are also reflected in the original_dict
outside the function. Like lists, dictionaries can affect the caller because they are passed by reference.6. Summary
Python’s “pass-by-reference” behaves differently depending on an object’s characteristics, so understanding it is necessary to improve your code’s reliability. In particular, to avoid unexpected behavior from passing references to mutable objects, it’s advisable to make use of copying and default argumentNone
.Summary Points
- Difference between pass-by-value and pass-by-reference: In Python, whether modifications inside a function affect the original variable depends on the object’s nature.
- Immutable vs. mutable: Immutable objects in Python do not reflect changes made inside a function, whereas mutable objects are shared between inside and outside the function via reference passing.
- Mitigation strategies: For mutable objects, methods such as using
deepcopy
from thecopy
module, or setting default arguments toNone
, are effective to avoid unexpected behavior.