So far, we’ve thought of functions as blocks of code—like recipes that we define and call upon to perform a task. But in Python, they are much more than that. Python treats functions as first-class citizens, which is a profound concept that unlocks many advanced and elegant programming patterns.
In this post, we’ll explore what it means for a function to be a “first-class citizen” and see how we can treat them just like any other object, such as a number, a string, or a list.
What is a “First-Class Citizen”?
In a programming language, a “first-class citizen” (or “first-class object”) is anything that can do the following:
- Be assigned to a variable.
- Be stored in a data structure (like a list or dictionary).
- Be passed as an argument to another function.
- Be returned as a value from another function.
In Python, functions meet all of these criteria. Let’s explore the first three.
1. Assigning a Function to a Variable
We got our first hint of this in Post #85, when we saw that writing a function’s name without parentheses ()
refers to the function object itself. Because it’s an object, we can assign it to a new variable, effectively giving the function another name.
def greet():
print("Hello, world!")
# Assign the function object 'greet' to a new variable 'say_hello'
say_hello = greet
# Now, 'say_hello' and 'greet' both refer to the same function object
print(greet)
print(say_hello)
# We can call the function using the new name
say_hello()
The output will show that both variables point to the same function object, and the call to say_hello()
works perfectly.
<function greet at 0x...>
<function greet at 0x...>
Hello, world!
2. Storing Functions in Data Structures
Since functions are objects, you can store them in lists, tuples, or dictionaries, just like any other value.
Functions in a List
def say_hello():
return "Hello"
def say_goodbye():
return "Goodbye"
# A list containing function objects
greetings = [say_hello, say_goodbye]
# We can loop through the list and call each function
for func in greetings:
print(func())
Output:
Hello
Goodbye
Functions in a Dictionary
This is a very powerful pattern for creating a “dispatcher” that can call different functions based on a string input.
def add(a, b):
return a + b
def subtract(a, b):
return a - b
operations = {
"add": add,
"subtract": subtract
}
# Look up the function in the dictionary and then call it
result = operations["add"](10, 5)
print(f"The result is: {result}") # Output: The result is: 15
3. Passing a Function as an Argument
A function that takes another function as an argument, or that returns a function, is called a higher-order function. This is a cornerstone of a programming style known as functional programming.
Let’s create a simple calculator
function that accepts two numbers and an “operation” function to perform on them.
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# This is a higher-order function because it takes a function as an argument
def calculator(a, b, operation):
# We call the function that was passed in
return operation(a, b)
# Pass the 'add' function object as an argument
add_result = calculator(10, 5, add)
print(f"The result of adding is: {add_result}")
# Pass the 'subtract' function object as an argument
subtract_result = calculator(10, 5, subtract)
print(f"The result of subtracting is: {subtract_result}")
When we call calculator(10, 5, add)
, we are passing the add
function object itself as an argument. The calculator
function then receives this object as its operation
parameter and can call it using operation(a, b)
.
What’s Next?
Thinking of functions as objects that you can pass around and store is a major step in your Python journey. This concept is the foundation for many powerful and elegant programming techniques, like decorators, which we will see later in the series.
We’ve seen that functions are self-contained blocks of code. But what if we need a helper function that is only ever used by one other function? Can we define a function inside another function? The answer is yes. In Post #105, we will explore nested functions.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com