Skip to content

Understanding First-Class Functions in Python


1. Introduction

One of the most common phrases we hear when learning Python is:

"Functions are first-class citizens."

But what does it mean exactly? Here is the explaination:

  • Everything in Python is object. A variable is an object.

  • A function in Python is just another object.

  • Therefore, Just like a variable (integer, a string, or a list), a function can be used to:

- stored in a variable
- passed to another function
- returned from a function
- placed inside a list or dictionary
- created at runtime

If we can treat functions the same way we treat other values, then functions are called first-class objects.


2. Everything in Python is an Object

In Python, nearly everything is an object.

x = 10
name = "Mujeeb"
numbers = [1, 2, 3]

- Each of these values is an object.
- We can assign them to variables.

Now lets consider a function.

def greet():
    print("Hello!")

Python actually creates a function object.

The variable greet simply refers to that object.


3: Variables Also Store References

Variables don't contain the object itself. They simply point to it.

flowchart LR

subgraph A["Function Reference"]
    G["greet"] --> F["Function Object<br/>code: print('Hello!')"]
end

subgraph B["Integer Reference"]
    X["x"] --> V["10"]
end

Variables point to objects.

Functions are objects.

Therefore variables can point to functions.


4. Assign a Function to Another Variable

def greet():
    print("Hello!")

say_hi = greet

Notice:

There are no parentheses.

We're copying the reference—not calling the function.

Now:

say_hi()

Output:

Hello!

Both variables refer to the exact same function object.

greet ─────┐
      +------------+
      | greet()    |
      +------------+
say_hi ────┘

5: Functions Can Live Inside Collections

Since functions are objects, they can be placed inside lists.

def add():
    print("Adding")

def delete():
    print("Deleting")

actions = [add, delete]

Now:

actions[0]()

Output:

Adding

The list stores references to functions.


6: Functions Can Be Passed as Arguments

Suppose we have:

def greet():
    print("Hello")

Another function can receive it.

def execute(func):
    func()

Now:

execute(greet)

Output:

Hello

Notice again:

We pass

greet

NOT

greet()

Because we want to pass the function itself—not its return value.

This is one of the most important ideas in Python.


7. Real-World Analogy

Imagine a remote control.

Calling the function:

greet()

is like pressing the button.

Passing the function:

greet

is like handing someone the remote.

They decide when to press the button.


8: Functions Can Return Functions

Since functions are just values, they can also be returned.

def make_printer():

    def printer():
        print("Printing...")

    return printer

Now:

p = make_printer()

What is p?

Not text.

Not a number.

It is another function.

p()

Output:

Printing...

This ability forms the basis of closures and decorators.


9: Higher-Order Functions

A function that

  • accepts another function, or
  • returns another function

is called a higher-order function.

Example:

def apply_twice(func, value):
    return func(func(value))

Suppose:

def double(x):
    return x * 2

Now:

apply_twice(double, 3)

Evaluation:

double(3)

6

double(6)

12

Result:

12

This works because functions are first-class objects.


10. Lambdas Are Also Function Objects

square = lambda x: x * x

This is simply another function object.

Equivalent to:

def square(x):
    return x * x

The lambda can be passed around just like any other function.

numbers = [1, 2, 3]

result = map(square, numbers)

or even:

result = map(lambda x: x * x, numbers)

Again, functions are values.


11. Why Python Was Designed This Way

Imagine if functions were not first-class.

We couldn't write:

sorted(names, key=len)

We couldn't use:

map()
filter()
reduce()

You couldn't create decorators.

Frameworks like Flask, FastAPI, and Django would be much more complicated.

Many elegant Python features rely on passing functions around as ordinary values.


12. A Mental Model

Instead of thinking:

"A function is something I call."

Think:

"A function is an object that can be called."

That's a subtle but important distinction.

Objects have properties.

One of the properties of a function object is that Python allows it to be invoked using parentheses.


13. Common Beginner Mistake

Call with parantheses

Consider:

execute(greet())

What happens?

Python first executes:

greet()

Suppose it returns:

None

Now Python actually runs:

execute(None)

Inside:

func()

Python tries:

None()

which produces:

TypeError: 'NoneType' object is not callable

The correct code is:

execute(greet)

without parentheses:

Remember:

greet

means

"the function"

while

greet()

means

"call the function now"


14. How This Leads to Decorators

Decorators work because functions are first-class.

def logger(func):

    def wrapper():
        print("Before")
        func()
        print("After")

    return wrapper

Notice what happens:

A function is received.
Another function is created.
That new function is returned.

Everything here is possible because functions are ordinary objects.


15. Key Takeaways

A function in Python is not just executable code—it is an object.

Because it is an object, it can be:

  • assigned to variables
  • stored in data structures
  • passed into other functions
  • returned from other functions
  • created dynamically

This property is known as being first-class.

Understanding this single concept unlocks many advanced Python features, including:

  • callbacks
  • closures
  • decorators
  • event handling
  • asynchronous programming
  • functional programming techniques