In Python, function arguments are pass by reference for mutable objects and pass by value for immutable objects. The concept of pass by reference and pass is value is similar in multiple programming languages. Understanding the function arguments concept and behavior of pass by reference vs. pass by value in Python is very crucial to avoid unexpected modifications to data and causing arbitrary results.
Pass by reference vs Pass by Value
Pass by reference means that a function receives the memory reference (or address) of the argument. It does not create a copy of the arguments value. Changes made to the argument inside the function will affect the original object outside the function as well.
Pass by value means the function receives a copy of the arguments value. It does not reference the actual object. Any changes made to the argument inside the function don’t affect the original object outside the function.
Python does not strictly follow pass by reference or pass by value. But it follows a pass by object reference model.
- If we pass a mutable object (like lists, dictionaries, sets, user-defined classes), the function can modify the original object (because both objects reference the same memory location).
- If we pass an immutable object (like integers, floats, strings, boolean or tuples), the function cannot modify the original object (because a new memory location is created parameter object and changes will not reflected in the original object).
Pass by reference example
# function arguments - pass by reference or pass by value
print("function arguments - pass by reference or pass by value")
def courses_reference(courses_list, course):
print(len(courses_list))
courses_list.append(course) # modify mutable object - will affect original object
courses = ["AWS","Python","ML","DevOps"] # list - mutable object
print("courses list before function call - ", courses)
courses_reference(courses, "Azure") # list (mutable object) - pass by reference as function argument
print("courses list after function call - ", courses) # courses elements after append
print("course added to - same reference of courses list")
- We have defined a function with 2 parameters
courses_reference(courses_list, course)
. It appendcourse
into thecourses_list
(mutable) object. - We have created a list (mutable) object =>
courses = ["AWS","Python","ML","DevOps"]
- Calling the function with argument (mutable object) =>
courses_reference(courses, "Azure")
. This argument object is mutable, it will be pass by reference. It means function,courses_list
parameter will refer the memory location of the passed object.courses_list
inside the function references the same list ascourses
outside the function. - When we append the
course
into thecourses_list
, it will affect the original argument list as well because lists are mutable and pass by reference. courses
list outside the function, will have thecourse
added to that list.
Program Output
function arguments - pass by reference or pass by value
courses list before function call - ['AWS', 'Python', 'ML', 'DevOps'] # original elements in list
4 # number of elements in passed argument
courses list after function call - ['AWS', 'Python', 'ML', 'DevOps', 'Azure'] # elements after adding course to the list
course added to - same reference of courses list
Pass by value example
def modify_number(n):
n += 10 # Creates a new integer, does not affect the original
number = 5
modify_number(number) # number (immutable) argument - pass by value
print(number) # Output => 5
- We have defined a function with 1 parameters
modify_number(n)
. It add another number into the parameter value. - Calling the function with argument (immutable object) =>
modify_number(number)
. This argument object is immutable, it will be pass by value. It means function,n
parameter will create a value of the passed object.n
inside the function does not refer the same object asnumber
which is outside the function. - When we add another number into the
n
, it does not affect the original number outside of function because numbers are immutable and pass by value. - The original number
number = 5
remains unchanged.
Pass by reference with broken reference
# function arguments - pass by reference, with broken reference
print("function arguments - pass by reference, with broken reference")
def courses_broken_reference(courses_list, course):
print(len(courses_list)) # length of original list
# creating local variable with same name. This will break the reference to argument object
courses_list = ["AWS","Python","ML","DevOps"]
courses_list.append(course) # element added to the local list object, argument object remains unchanged
courses = ["AWS","Python","ML","DevOps"] # list - mutable object
print("courses list before function call - ", courses)
courses_broken_reference(courses, "Azure") # list (mutable object) - pass by reference as function argument
print("courses list after function call - ", courses) # courses elements after append
print("course added was in - broken reference of courses list")
- We have defined a function with 2 parameters
courses_broken_reference(courses_list, course)
. - We have created a list (mutable) object =>
courses = ["AWS","Python","ML","DevOps"]
- Calling the function with argument (mutable object) =>
courses_broken_reference(courses, "Azure")
. This argument object is mutable, it will be pass by reference. It means function,courses_list
parameter will refer the memory location of the passed object.courses_list
inside the function references the same list ascourses
outside the function. - But we break the reference inside the function. When we created a local variable
courses_list = ["AWS","Python","ML","DevOps"]
, which has the same name as parameter variable. Now operations inside the function will happen on this local variable and reference to passed argument is broken. - When we append the
course
into thecourses_list
, this happens on the local variable. Reference to argument list is broken and will not affect the original list outside the function. courses
list outside the function will not change.
Program Output
function arguments - pass by reference, with broken reference
courses list before function call - ['AWS', 'Python', 'ML', 'DevOps'] # original elements in the list
4 # number of elements in the original list
courses list after function call - ['AWS', 'Python', 'ML', 'DevOps'] # elements after broken reference
course added was in - broken reference of courses list
Pass by reference with immutable object
Immutable objects can be passed by reference, with wrapping into a mutable object. like tuple into a list or numbers into a list.
# pass by reference - with wrapping immutable object
print("pass by reference - with wrapping immutable object")
def modify_number(n):
n[0] += 10 # Modifies the element inside the list
number_list = [5] # Integer wrapped in a list
modify_number(number_list)
print(number_list[0]) # Output => 15
- We have defined a function with 1 parameters
modify_number(n)
. Here we are takingn
as a list and adding another number at its first index value. number_list = [5]
defines the list of numbers. It wraps immutable number into a mutable list object.- Calling the function with argument (mutable object) =>
modify_number(number_list)
. This argument object is mutable, it will be pass by reference. - When we add another number into the first index of list
n
, it will affect the originalnumber_list
outside of function because lists are mutable and pass by reference. - The original
number_list = [15]
has updated value.
Function Annotations
Python allows adding metadata to function parameters and return values via annotations. Function annotations are optional and can be used for documentation or type hinting.
def add(a: int, b: int) -> int:
return a + b
These annotations don’t enforce datatype for the variable. We can still call the function with different datatype argument. e.g. we can call add("shbytes", "courses")
with string arguments. These annotations only serve as guidelines or hints for developers and IDEs.
Higher Order Functions
A function is called a higher-order function if it:
- Takes one or more functions as arguments.
- Returns a function as its result.
In Python, a function is allowed to take another function as an argument and can return a function as a result.
# Higher Order Functions
def apply_function(func, value):
return func(value) # call the parameter function with argument
# call function with lambda function and value as arguments
print(apply_function(lambda x: x * 2, 10)) # Output => 20
- We have created a function with 2 parameters =>
apply_function(func, value)
. This function takes another function as an argument and called this function argument value. apply_function(lambda x: x * 2, 10)
=> This calls the function with lambda function and initial value as an argument. Insideapply_function
, lambda function will be called with argument value10
. lambda function will calculate10 * 2
and return its value.
Summary
Functions in Python are powerful tools for creating reusable, modular, and efficient code. By mastering function definitions, parameters, return values, scope, and advanced techniques like recursion and lambda expressions, we can write more robust and maintainable Python code. Following topics were discussed in this article.
Code – Github Repository
All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.
Python Topics
Interview Questions & Answers
Q: What is the difference between a function and a method in Python?
- A function is a block of code that can be called by its name and is independent of any object.
- A method is similar to a function but is associated with an object. Methods are defined inside classes and typically operate on data contained in the object (instance).
# This is a function
def shbytes():
print("Python")
class Learning:
# This is a method inside a class
def shbytes(self):
print("Python")
Q: What is function overloading in Python? Does Python support it?
Function overloading refers to defining multiple functions with the same name but different parameter types or counts.
Python being dynamically typed language, does not support traditional function overloading. However, we can achieve similar behavior by using default arguments or checking argument types inside the function.