Learning Objectives
After completing this lesson, you will be able to:- Explain why functions are objects.
- Pass and return functions.
- Understand higher-order functions.
- Build and use decorators.
- Understand closures and their relationship with decorators.
Functions are Objects
Like integers, strings, lists, and dictionaries, functions are also objects. Therefore, a function can:- Be assigned to a variable.
- Be passed as an argument.
- Be returned from another function.
- Be stored in a collection.
Assigning a Function
Storing Functions
Practice
Exercise 1
Predict the output.Solution
Solution
msg refers to the same function object as welcome.Exercise 2
What is the difference between the following statements?Solution
Solution
f = greetassigns the function object.f = greet()calls the function and stores its return value.
Higher-Order Functions
A higher-order function is a function that:- Accepts one or more functions as arguments.
- Returns a function.
Passing Functions as Arguments
Returning Functions
Example
Practice
Exercise 1
Predict the output.Solution
Solution
Exercise 2
Predict the output.Solution
Solution
Exercise 3
When is a function called a higher-order function?Solution
Solution
A function is called a higher-order function if it:
- Accepts one or more functions as arguments.
- Returns a function.
Higher-order functions form the foundation for closures and decorators.
Closures
Sometimes we want a function to remember information from previous function calls. A normal function cannot do this because its local variables are destroyed when the function finishes executing.Example: Normal Function
counter() is called, the local variable count is created again and initialized to 0. Therefore, the function cannot remember its previous state.
To preserve the state between function calls, we can use a closure.
What is a Closure?
A closure is an inner function that remembers the variables of its enclosing function even after the enclosing function has finished executing. A closure is created when:- A function is defined inside another function.
- The inner function uses variables from the outer function.
- The inner function is returned.
Example
count is preserved even after counter() has finished executing. Each call to increment() updates the same variable instead of creating a new one.
The nonlocal keyword allows the inner function to modify a variable defined in the enclosing function.
Practice
Exercise 1
Predict the output.Solution
Solution
message even after outer() has finished executing.Exercise 2
Predict the output.Solution
Solution
count is preserved inside the closure and updated on each function call.Exercise 3
Why do we use closures?Solution
Solution
Closures allow a function to remember and preserve variables from its enclosing function even after the enclosing function has finished executing.
Closures are widely used for state preservation and form the foundation of decorators, where the wrapper function remembers the original function passed to the decorator.
Decorators
A decorator is a function that extends or modifies the behavior of another function without changing its original code. A decorator is a higher-order function because it:- Accepts a function as an argument.
- Returns another function.
Creating a Decorator
greet(), the decorator returns a new function with additional behavior.
Using the @ Syntax
Python provides the @ syntax as a convenient way to apply decorators.
Practice
Exercise 1
Predict the output.Solution
Solution
Exercise 2
Which statement is equivalent to the following code?Solution
Solution
@ syntax is a shorthand for applying a decorator.Decorating Functions with Parameters
The previous decorator works only for functions that do not accept any arguments.wrapper() does not accept any arguments, Python raises an error.
*argscollects all positional arguments.**kwargscollects all keyword arguments.func(*args, **kwargs)forwards all arguments to the original function.
Thewrapper()function is defined inside another function and remembers the originalfunceven after the outer function has finished executing. This behavior was possible because of closure.
Practice & Exercises
To reinforce what you’ve learned in this section (Functions as objects, Higher-order functions, Closures, and Decorators), practice with these interactive notebooks:Follow-Along Practice
Practice passing and returning functions, preserving state with closures using nonlocal, and creating custom decorators with arguments.💻 VS Code | 🚀 Colab | 📥 Download
Practice Exercises
Test your skills with exercises on higher-order function mapping, prefix greeting closures, timer decorators, argument uppercase decorators, and call counter decorators.💻 VS Code | 🚀 Colab | 📥 Download