Nearby lessons
63 of 108Python - Functions
Introduction to Functions
While writing programs, sometimes we need to write the same group of statements again and again.
Writing the same code repeatedly is not a good programming practice because it increases the size of the program and makes maintenance difficult.
Instead of rewriting the same statements multiple times, we can group them together into a single unit and use that unit whenever required.
This single unit is called a Function.
A function allows us to write the code once and execute it many times by simply calling the function.
Definition of Function
A Function is a group of related statements that performs a specific task.
Once a function is created, it can be called whenever required without rewriting the same code.
Real-Life Example
Suppose a school management system needs to print the following message many times:
Hello Students Welcome to Python Class
Instead of writing these statements repeatedly, we can place them inside a function and call that function whenever needed.
Advantages of Functions
According to the tutorial, the main advantage of functions is Code Reusability.
Functions also provide several additional benefits.
- Code Reusability.
- Reduces duplicate code.
- Improves readability.
- Makes programs easier to maintain.
- Reduces program size.
- Makes debugging easier.
- Improves modular programming.
Code Reusability
Code Reusability means writing the code once and using it many times.
Instead of copying the same statements into different parts of the program, we simply call the function.
This saves both time and effort.
Types of Functions
Python supports two types of functions.
- Built-in Functions
- User Defined Functions
1. Built-in Functions
Functions that are already available in Python are called Built-in Functions or Predefined Functions.
These functions are automatically available after installing Python.
We do not need to write their implementation.
Common Built-in Functions
main.py
No output captured.
Example
main.py
6 30
2. User Defined Functions
Functions created by the programmer according to business requirements are called User Defined Functions.
These functions are written using the def keyword.
Syntax of User Defined Function
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
def |
Keyword used to define a function. |
| function_name | Name of the function. |
| parameters | Input values accepted by the function. |
| Doc String | Description of the function. |
| statements | Task performed by the function. |
| return | Returns the result to the caller. |
The def Keyword
The def keyword is used to create a User Defined Function.
Every function definition begins with the def keyword.
Syntax
main.py
No output captured.
First Function Program
main.py
Hello Good Morning Hello Good Morning Hello Good Morning
Understanding the Program
def wish():
Defines a function named wish().
print("Hello Good Morning")
This statement is executed whenever the function is called.
wish()
Calls the function.
Since the function is called three times, the message is printed three times.
Calling a Function
A function is executed only when it is called.
Simply defining a function does not execute it.
Syntax
main.py
No output captured.
Example
main.py
Welcome
Important Point
Merely defining a function does not execute it.
The function body is executed only when the function is called.
Difference Between Defining and Calling a Function
| Defining Function | Calling Function |
|---|---|
| Creates the function. | Executes the function. |
Uses def. |
Uses the function name followed by parentheses. |
| Executed only once. | Can be executed any number of times. |
Summary
| Topic | Description |
|---|---|
| Function | Group of statements written as a single unit. |
| Main Advantage | Code Reusability. |
| Built-in Functions | Functions provided by Python. |
| User Defined Functions | Functions created by the programmer. |
| def | Keyword used to define a function. |
| Function Call | Executes the function. |
Important Notes
- A function is a group of statements that performs a specific task.
- The main advantage of functions is Code Reusability.
- Python supports Built-in Functions and User Defined Functions.
- Built-in Functions are available automatically with Python.
- User Defined Functions are created by the programmer.
- The
defkeyword is used to define a function. - Defining a function does not execute it.
- A function executes only when it is called.
- In other programming languages, functions may also be called methods, procedures, or subroutines.
Function Parameters and Arguments
Functions become more useful when they can accept input values.
These input values are called Arguments and they are received by the function through Parameters.
Parameters allow the same function to work with different values without changing the function code.
Parameters and Arguments
There are two important terms in Functions:
- Formal Parameters
- Actual Arguments
Formal Parameters
The variables declared inside the function definition are called Formal Parameters.
They receive values from the function call.
Actual Arguments
The values passed while calling a function are called Actual Arguments.
These values are copied into the formal parameters.
Example
main.py
Hello Durga Hello Ravi Hello Sunny
Explanation
In the above program:
nameis the Formal Parameter."Durga","Ravi"and"Sunny"are the Actual Arguments.- Every time the function is called, the argument value is assigned to the parameter.
Types of Arguments
Python supports different types of arguments.
- Positional Arguments
- Keyword Arguments
- Default Arguments
- Variable Length Arguments (covered in the next part)
1. Positional Arguments
In Positional Arguments, values are assigned to parameters according to their position.
The first argument is assigned to the first parameter, the second argument to the second parameter, and so on.
Example
main.py
80
Explanation
| Parameter | Argument |
|---|---|
| a | 100 |
| b | 20 |
Since the arguments follow the correct order, the subtraction result is 80.
Changing the Position
main.py
-80
Explanation
Because positional arguments depend on their position, changing the order changes the result.
Rules of Positional Arguments
- The number of arguments must match the number of parameters.
- The order of arguments is very important.
- Changing the order changes the result.
2. Keyword Arguments
In Keyword Arguments, values are passed using the parameter names.
Since the parameter name is specified, the order of arguments does not matter.
Syntax
main.py
No output captured.
Example 1
main.py
Hello Durga Good Morning
Example 2
main.py
Hello Durga Good Morning
Explanation
Although the order of the arguments is changed, the output remains the same because values are assigned using parameter names.
Advantages of Keyword Arguments
- Arguments can be supplied in any order.
- Programs become easier to read.
- The possibility of assigning incorrect values is reduced.
Mixing Positional and Keyword Arguments
Python allows positional and keyword arguments to be used together.
However, positional arguments must always come before keyword arguments.
Correct Example
main.py
Hello Durga Good Morning
Incorrect Example
main.py
SyntaxError: Positional argument follows keyword argument
Important Rule
Positional arguments must always appear before keyword arguments.
A positional argument cannot appear after a keyword argument.
3. Default Arguments
Sometimes we want a parameter to have a default value.
If the caller does not supply a value, the default value is used automatically.
Syntax
main.py
No output captured.
Example
main.py
Hello Guest Hello Durga Hello Ravi
Explanation
During the first function call, no argument is passed.
Therefore, the default value "Guest" is used.
During the remaining calls, the supplied arguments replace the default value.
Rules for Default Arguments
- Default parameters must be declared after non-default parameters.
- A default value is used only when no argument is supplied.
- If an argument is supplied, the default value is ignored.
Correct Example
main.py
No output captured.
Incorrect Example
main.py
SyntaxError: non-default argument follows default argument
Comparison of Argument Types
| Argument Type | Assignment Method | Order Required |
|---|---|---|
| Positional | Based on position. | Yes |
| Keyword | Based on parameter name. | No |
| Default | Uses predefined value if no argument is supplied. | No |
Summary
| Topic | Description |
|---|---|
| Formal Parameter | Variable declared in the function definition. |
| Actual Argument | Value passed during the function call. |
| Positional Argument | Arguments assigned according to position. |
| Keyword Argument | Arguments assigned using parameter names. |
| Default Argument | Uses a predefined value when no argument is supplied. |
Important Notes
- Formal Parameters receive values from Actual Arguments.
- Positional Arguments depend on the order of values.
- Keyword Arguments depend on parameter names.
- Keyword Arguments can be supplied in any order.
- Positional Arguments must appear before Keyword Arguments.
- Default Arguments provide default values for parameters.
- Default parameters must always come after non-default parameters.
- If a value is supplied, the default value is ignored.
Introduction to Variable Length Arguments
In the previous section, we learned that a function can receive parameters.
Normally, the number of arguments passed to a function must exactly match the number of formal parameters.
If the number of arguments is different, Python raises an error.
Sometimes, we do not know in advance how many arguments will be passed to a function.
In such situations, Python provides Variable Length Arguments.
Variable Length Arguments allow a function to accept any number of arguments.
Why Do We Need Variable Length Arguments?
Consider a program that calculates the sum of numbers.
Sometimes the user wants to add two numbers, sometimes three numbers, and sometimes ten numbers.
If we use normal parameters, we have to create different functions for every possible case.
This increases code duplication and makes the program difficult to maintain.
Variable Length Arguments solve this problem by allowing a single function to accept any number of values.
Problem with Normal Parameters
main.py
30 TypeError: add() takes 2 positional arguments but 3 were given
Explanation
The function add() is defined with only two parameters:
a, b
The first function call passes two arguments, so it executes successfully.
The second function call passes three arguments.
Since the function expects only two arguments, Python raises a TypeError.
This is one of the biggest limitations of normal parameters.
Solution - Variable Length Arguments
Python provides the * (asterisk) operator to solve this problem.
The * operator allows a function to receive any number of positional arguments.
All the arguments are automatically collected into a single tuple.
Syntax
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
* |
Indicates Variable Length Positional Arguments. |
args |
Stores all arguments inside a tuple. |
| function_name | Name of the function. |
Important Point
The name args is not a keyword.
It is only a naming convention.
You can use any valid variable name after the * operator.
Example
main.py
() (10,) (10, 20) (10, 20, 30)
Understanding the Program
Whenever the function is called, Python collects all positional arguments into a tuple.
The tuple is stored inside the variable args.
The number of arguments can be zero, one, two, or any number.
Therefore, the same function works for every function call.
How Python Stores the Arguments
| Function Call | args Value |
|---|---|
display() |
() |
display(10) |
(10,) |
display(10,20) |
(10,20) |
display(10,20,30) |
(10,20,30) |
Advantages of *args
- Accepts any number of positional arguments.
- Removes the limitation of fixed parameters.
- Reduces duplicate functions.
- Improves code reusability.
- Makes functions more flexible.
Real-World Applications
Variable Length Arguments are commonly used in:
- Calculator applications.
- Logging utilities.
- Mathematical operations.
- Data processing utilities.
- Framework development.
Quick Summary
| Concept | Description |
|---|---|
| Normal Parameters | Accept a fixed number of arguments. |
| Variable Length Arguments | Accept any number of arguments. |
*args |
Collects all positional arguments into a tuple. |
| Data Type of args | Tuple |
Important Notes
*argsaccepts any number of positional arguments.- All arguments are stored as a tuple.
argsis only a variable name, not a keyword.- The variable name can be changed.
- Variable Length Arguments remove the limitation of fixed parameters.
- Functions become more flexible and reusable.
Working with *args
In the previous section, we learned that *args collects any number of positional arguments into a tuple.
Now let's understand how to work with *args by using different examples.
Since args is a tuple, we can perform all tuple operations on it such as:
- Traversing
- Indexing
- Finding Length
- Calculating Sum
Example 1 - Print All Arguments
main.py
(10, 20, 30, 40)
('Python', 'Java', 'C++')Explanation
All positional arguments are collected into a tuple.
The tuple is printed directly.
The number of arguments can be different in every function call.
Example 2 - Traversing *args
main.py
10 20 30 40
Explanation
Since args is a tuple, we can traverse it by using a for loop.
Each argument is printed one by one.
Example 3 - Count Total Arguments
main.py
Total Arguments = 0 Total Arguments = 1 Total Arguments = 2 Total Arguments = 5
Explanation
The built-in len() function returns the total number of elements stored in the tuple.
This allows us to determine how many arguments were passed to the function.
Example 4 - Calculate the Sum
main.py
30 60 150
Explanation
The parameter numbers stores all arguments as a tuple.
The sum() function calculates the total of all tuple elements.
Example 5 - Find Maximum Value
main.py
30 100
Explanation
The built-in max() function returns the largest value from the tuple.
Example 6 - Find Minimum Value
main.py
10 50
Example 7 - Accept Different Data Types
main.py
100 Python 10.5 True
Explanation
*args can store values of different data types because tuples support heterogeneous elements.
How *args Works
| Function Call | Tuple Created |
|---|---|
display() |
() |
display(10) |
(10,) |
display(10,20) |
(10,20) |
display(10,20,30) |
(10,20,30) |
display(10,20,30,40) |
(10,20,30,40) |
Advantages of *args
- Accepts unlimited positional arguments.
- Eliminates the need for multiple overloaded functions.
- Reduces duplicate code.
- Improves code reusability.
- Makes functions flexible.
- Useful when the number of inputs is unknown.
Real-World Applications
- Calculator applications.
- Shopping cart total calculation.
- Statistical calculations.
- Logging systems.
- Data processing libraries.
- Framework development.
Summary
| Operation | Description |
|---|---|
| Display all arguments. | |
| Traversal | Use a for loop. |
| Count | Use len(args). |
| Sum | Use sum(args). |
| Maximum | Use max(args). |
| Minimum | Use min(args). |
Important Notes
*argsstores all positional arguments in a tuple.- Since it is a tuple, all tuple operations are supported.
- The number of arguments can vary for each function call.
- The parameter name
argscan be replaced with any valid identifier. len(),sum(),max(), andmin()can be used directly with*args.*argsis commonly used in Python libraries and frameworks.
Combining Normal Parameters with *args
In the previous section, we learned that *args can accept any number of positional arguments.
Sometimes, a function requires one or more fixed parameters along with additional variable-length arguments.
Python allows us to combine Normal Parameters and *args in the same function.
The fixed values are received by the normal parameters, and all remaining positional arguments are collected into *args.
Syntax
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
| parameter1 | Receives the first positional argument. |
| parameter2 | Receives the second positional argument. |
| *args | Collects all remaining positional arguments into a tuple. |
Example 1 - One Normal Parameter
main.py
Name : Rahul Marks : (80, 90, 95) Name : Neha Marks : (70, 75)
Explanation
The first argument is assigned to the normal parameter name.
All remaining arguments are collected into the tuple marks.
Example 2 - Two Normal Parameters
main.py
Name : Rahul
Age : 20
Subjects : ('Python', 'Java', 'React')Explanation
The first argument is assigned to name.
The second argument is assigned to age.
All remaining arguments are stored inside subjects as a tuple.
Example 3 - Sum of Remaining Numbers
main.py
Addition of Numbers Sum = 100 Another Example Sum = 30
Explanation
The first argument is stored in title.
The remaining numeric values are collected into numbers.
The sum() function calculates the total of all values stored in numbers.
Rules for Combining Normal Parameters and *args
- Normal parameters must appear before
*args. *argsshould be the last positional parameter.- Python first assigns values to the normal parameters.
- All remaining positional arguments are stored in
*args.
Correct Example
main.py
10 20 (30, 40, 50)
How Python Assigns Values
| Argument | Assigned To |
|---|---|
| 10 | a |
| 20 | b |
| 30 | args Tuple |
| 40 | |
| 50 |
Incorrect Example
main.py
TypeError: missing required keyword-only argument: 'a'
Why Does This Error Occur?
After *args, every parameter becomes a keyword-only parameter.
Therefore, the parameter a must be supplied using its name.
It cannot receive a positional argument.
Correct Way
main.py
(10, 20, 30) 40
Comparison Table
| Feature | Normal Parameter | *args |
|---|---|---|
| Accepts | One Value | Multiple Values |
| Data Type | Depends on Input | Tuple |
| Position | Before *args | After Normal Parameters |
| Purpose | Required Values | Additional Values |
Real-World Applications
- Student management systems where a student has a fixed name but variable subjects.
- Billing systems where the customer name is fixed but purchased items vary.
- Employee systems where employee details are fixed but allowances vary.
- Framework APIs that accept mandatory parameters along with optional values.
Summary
| Concept | Description |
|---|---|
| Normal Parameters | Receive fixed positional arguments. |
| *args | Receives all remaining positional arguments. |
| Order | Normal parameters must come before *args. |
| Data Type of args | Tuple. |
Important Notes
- Normal parameters receive fixed arguments.
*argsreceives all remaining positional arguments.- Python first fills the normal parameters.
- The remaining positional arguments are stored in a tuple.
- Parameters written after
*argsbecome keyword-only parameters. - The name
argsis only a convention and can be replaced with any valid identifier.
Introduction to **kwargs
In the previous sections, we learned about *args, which accepts any number of positional arguments.
Python also provides **kwargs, which accepts any number of keyword arguments.
Keyword arguments are passed using the syntax parameter=value.
All keyword arguments are automatically collected into a Dictionary.
Why Do We Need **kwargs?
Sometimes we do not know in advance how many keyword arguments will be passed to a function.
Instead of creating multiple parameters, we can use **kwargs.
This makes the function flexible and reusable.
Syntax
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
** |
Indicates Variable Length Keyword Arguments. |
kwargs |
Stores all keyword arguments in a Dictionary. |
| function_name | Name of the function. |
Important Point
The name kwargs is not a Python keyword.
It is only a naming convention.
You may use any valid variable name after **.
Example 1 - Print Keyword Arguments
main.py
{}
{'name': 'Durga'}
{'name': 'Durga', 'age': 35}
{'name': 'Durga', 'age': 35, 'city': 'Hyderabad'}Explanation
Each keyword argument is stored as a key-value pair inside the Dictionary kwargs.
The function can receive zero, one, or many keyword arguments.
Example 2 - Traversing **kwargs
main.py
name = Rahul age = 20 course = Python
Explanation
Since kwargs is a Dictionary, we can use the items() method to traverse all key-value pairs.
Example 3 - Using Normal Parameters with **kwargs
main.py
Name : Rahul
Details : {'age': 20, 'city': 'Delhi', 'course': 'Python'}Explanation
The normal parameter name receives the first positional argument.
All keyword arguments are collected into the Dictionary details.
Rules for **kwargs
**kwargsaccepts only keyword arguments.- All keyword arguments are stored in a Dictionary.
- Keys represent parameter names.
- Values represent the supplied values.
- The variable name
kwargscan be replaced with any valid identifier.
Difference Between *args and **kwargs
| Feature | *args | **kwargs |
|---|---|---|
| Accepts | Positional Arguments | Keyword Arguments |
| Data Type | Tuple | Dictionary |
| Symbol | * | ** |
| Access Method | Loop through tuple | Loop through Dictionary |
| Example | fun(10,20,30) |
fun(a=10,b=20) |
Comparison of Normal Parameters, *args and **kwargs
| Feature | Normal Parameter | *args | **kwargs |
|---|---|---|---|
| Accepts | Fixed Arguments | Variable Positional Arguments | Variable Keyword Arguments |
| Data Type | Depends on Value | Tuple | Dictionary |
| Flexibility | Low | High | High |
Real-World Applications
- Configuration settings.
- API development.
- Framework development (Django, Flask, FastAPI).
- Passing optional settings.
- Database configuration.
- Logging utilities.
Summary
| Concept | Description |
|---|---|
**kwargs |
Accepts any number of keyword arguments. |
| Storage | Dictionary. |
| Key | Parameter Name. |
| Value | Supplied Value. |
| Traversal | Using items(). |
Important Notes
**kwargsaccepts any number of keyword arguments.- All keyword arguments are stored in a Dictionary.
kwargsis not a keyword; it is only a variable name.- Dictionary methods like
keys(),values(), anditems()can be used withkwargs. *argsstores positional arguments in a Tuple.**kwargsstores keyword arguments in a Dictionary.- Both
*argsand**kwargsmake functions flexible and reusable.
Return Statement
When a function completes its execution, sometimes it needs to send a result back to the function caller.
To send the result from a function, Python provides the return statement.
The return statement terminates the execution of the function and transfers control back to the calling statement.
If a value is specified after the return keyword, that value is returned to the caller.
Why Do We Need the Return Statement?
Consider a function that adds two numbers.
If the function only prints the result, the result cannot be used elsewhere in the program.
If the function returns the result, it can be stored in a variable, used in calculations, or passed to another function.
Therefore, returning values makes functions more useful and reusable.
Syntax
main.py
No output captured.
Syntax Explanation
| Statement | Purpose |
|---|---|
return value |
Returns the specified value to the caller. |
return |
Terminates the function without returning any value. |
Example 1 - Function Returning a Value
main.py
30
Explanation
The function receives two numbers.
It calculates their sum and returns the result.
The returned value is stored in the variable result.
Finally, the value is printed.
Example 2 - Returning an Expression
main.py
25 100
Explanation
The expression n * n is evaluated first.
The calculated value is then returned to the caller.
Example 3 - Returning a String
main.py
Welcome to Python
Example 4 - Returning a Boolean Value
main.py
True False
Example 5 - Returning a List
main.py
['Red', 'Green', 'Blue']
Example 6 - Function Without Return Statement
main.py
Hello None
Explanation
The function prints the message.
Since there is no return statement, Python automatically returns None.
Therefore, the variable result stores None.
Example 7 - Empty Return Statement
main.py
Start
Explanation
When Python encounters the return statement, the function immediately terminates.
The statement after return is never executed.
Flow of Return Statement
| Step | Action |
|---|---|
| 1 | Function is called. |
| 2 | Function executes its statements. |
| 3 | return sends the result back. |
| 4 | Function execution stops. |
| 5 | Control returns to the caller. |
Difference Between print() and return
| print() | return |
|---|---|
| Displays output on the screen. | Returns a value to the caller. |
| Does not terminate the function. | Terminates the function immediately. |
| Cannot be reused directly. | The returned value can be reused anywhere. |
| Mainly used for displaying information. | Mainly used for sending results back. |
Real-World Applications
- Returning calculated values from mathematical functions.
- Returning database query results.
- Returning API responses.
- Returning validation results.
- Returning processed data from helper functions.
Summary
| Concept | Description |
|---|---|
return value |
Returns a value to the caller. |
return |
Terminates the function. |
| No return statement | Python returns None. |
| After return | Remaining statements are not executed. |
| Purpose | Send results back to the caller. |
Important Notes
- The
returnstatement sends a value back to the caller. - It immediately terminates the function.
- A function can return numbers, strings, lists, tuples, dictionaries, Boolean values, or objects.
- If no
returnstatement is written, Python automatically returnsNone. - Statements written after
returnare never executed. - The returned value can be stored in a variable or passed to another function.
returnis different fromprint();print()displays output, whereasreturnsends data back to the caller.
Returning Multiple Values from a Function
In the previous section, we learned how a function can return a single value by using the return statement.
Python also allows a function to return multiple values.
This is one of the powerful features of Python because many programming languages can return only one value directly.
When multiple values are returned, Python automatically packs them into a Tuple.
Why Return Multiple Values?
Sometimes a function performs multiple calculations and needs to send several results back to the caller.
For example:
- Returning addition, subtraction, multiplication and division together.
- Returning student name, marks and grade.
- Returning minimum and maximum values.
- Returning multiple statistics from a dataset.
Instead of calling multiple functions, Python allows us to return all results together.
Syntax
main.py
No output captured.
Important Point
Although multiple values appear to be returned, Python actually returns a single Tuple.
Python automatically performs Tuple Packing.
Example 1 - Returning Multiple Values
main.py
(30, 10, 200, 2.0)
Explanation
The function returns four values.
Python automatically packs these values into a tuple.
Therefore, the variable result stores a tuple.
Tuple Packing
When multiple values are returned, Python automatically creates a tuple.
This process is called Tuple Packing.
Example
main.py
(10, 20, 30)
Receiving Multiple Returned Values
Instead of storing the returned tuple in a single variable, we can receive each value into separate variables.
This process is called Tuple Unpacking.
Example
main.py
Addition = 30 Subtraction = 10 Multiplication = 200 Division = 2.0
Explanation
The returned tuple contains four values.
Each value is automatically assigned to the corresponding variable.
This process is known as Tuple Unpacking.
Example 2 - Returning Student Information
main.py
Rahul 90 A
Example 3 - Returning Minimum and Maximum Values
main.py
Minimum = 10 Maximum = 80
Example 4 - Returning Different Data Types
main.py
(101, 'Python', True, 95.5)
Example 5 - Returning a Tuple Explicitly
main.py
(1, 2, 3)
Automatic Tuple Packing
| Return Statement | Python Stores As |
|---|---|
return 10,20 |
(10,20) |
return 10,20,30 |
(10,20,30) |
return "A",100 |
("A",100) |
return True,50.5 |
(True,50.5) |
Difference Between Single Return and Multiple Return
| Single Return | Multiple Return |
|---|---|
| Returns one value. | Returns multiple values. |
| Any data type. | Automatically packed into a tuple. |
| Stored in one variable. | Can be stored in one variable or unpacked into multiple variables. |
Real-World Applications
- Returning multiple calculation results.
- Returning database records.
- Returning API response values.
- Returning student information.
- Returning minimum and maximum values.
- Returning statistical information.
Summary
| Concept | Description |
|---|---|
| Multiple Return | Return more than one value. |
| Tuple Packing | Python automatically creates a tuple. |
| Tuple Unpacking | Assign returned values to multiple variables. |
| Storage | Tuple. |
| Advantage | Return multiple results using one function. |
Important Notes
- Python supports returning multiple values from a function.
- Multiple returned values are automatically packed into a tuple.
- This automatic conversion is called Tuple Packing.
- The returned tuple can be stored in a single variable.
- It can also be unpacked into multiple variables.
- The number of receiving variables should match the number of returned values.
- Multiple return values make functions more reusable and efficient.
Introduction to Variables in Functions
Variables are used to store data in a program.
Depending on where a variable is declared, Python classifies variables into different types.
Python supports two types of variables:
- Global Variables
- Local Variables
Understanding the scope of variables is very important because it determines where a variable can be accessed and modified.
Function vs Module vs Library
Before learning Global and Local Variables, it is important to understand three related terms.
| Term | Description |
|---|---|
| Function | A group of statements written together to perform a specific task. |
| Module | A file that contains one or more functions. |
| Library | A collection of multiple related modules. |
Global Variables
The variables declared outside of every function are called Global Variables.
Global variables belong to the entire module.
Every function inside the same module can access global variables unless a local variable with the same name exists.
Characteristics of Global Variables
- Declared outside all functions.
- Accessible throughout the module.
- Can be shared by multiple functions.
- Remain available until the program finishes.
Program: Accessing a Global Variable
main.py
10 10
Understanding the Program
The variable a is declared outside every function.
Therefore, it becomes a Global Variable.
Both f1() and f2() can access the same variable.
No separate copy of the variable is created for each function.
Scope of Global Variables
| Declared Outside Function? | Accessible Inside Function? | Accessible by Multiple Functions? |
|---|---|---|
| Yes | Yes | Yes |
Local Variables
The variables declared inside a function are called Local Variables.
A local variable exists only while the function is executing.
After the function completes, the local variable is destroyed.
It cannot be accessed from outside the function in which it is declared.
Characteristics of Local Variables
- Declared inside a function.
- Accessible only inside that function.
- Cannot be accessed from outside the function.
- Created when the function starts executing.
- Destroyed after the function finishes execution.
Program: Local Variable
main.py
10 NameError: name 'a' is not defined
Understanding the Program
The variable a is created inside f1().
Therefore, it is a Local Variable.
It is available only while f1() is executing.
When f2() tries to access it, Python cannot find the variable and raises a NameError.
Lifetime of a Local Variable
| Event | Local Variable |
|---|---|
| Function starts | Created |
| Function executes | Available |
| Function ends | Destroyed |
Difference Between Global and Local Variables
| Global Variable | Local Variable |
|---|---|
| Declared outside functions. | Declared inside functions. |
| Accessible throughout the module. | Accessible only inside its function. |
| Can be shared by multiple functions. | Cannot be shared outside the function. |
| Exists throughout program execution. | Exists only while the function executes. |
Real-World Applications
- Global variables are used for application-wide configuration settings.
- Global variables can store constants shared by many functions.
- Local variables are used for temporary calculations.
- Loop counters and intermediate results are generally local variables.
- Keeping temporary values local improves program safety and readability.
Quick Summary
| Topic | Description |
|---|---|
| Global Variable | Declared outside a function. |
| Local Variable | Declared inside a function. |
| Scope of Global Variable | Entire module. |
| Scope of Local Variable | Only inside the function. |
| Lifetime of Local Variable | Until the function completes execution. |
Important Notes
- Python supports Global Variables and Local Variables.
- Global variables are declared outside functions.
- Local variables are declared inside functions.
- Global variables can be accessed by all functions in the same module.
- Local variables are available only within the function where they are declared.
- A local variable is created when the function starts and destroyed when the function ends.
- Attempting to access a local variable outside its function results in a
NameError.
The global Keyword
In the previous section, we learned that a Global Variable can be accessed inside a function.
However, if we try to modify a Global Variable directly inside a function, Python creates a new Local Variable instead of modifying the Global Variable.
To modify a Global Variable inside a function, we must use the global keyword.
The global keyword tells Python that the variable belongs to the Global Scope and not to the Local Scope.
Syntax
main.py
No output captured.
Syntax Explanation
| Keyword | Purpose |
|---|---|
global |
Allows a function to modify a Global Variable. |
Example 1 - Accessing a Global Variable
main.py
10 10
Explanation
The variable a is declared outside the function.
Since the function only reads the variable, the global keyword is not required.
Example 2 - Modifying Without global
main.py
20 10
Explanation
The assignment a = 20 creates a new Local Variable.
The Global Variable remains unchanged.
Therefore, the function prints 20, but outside the function the value is still 10.
Example 3 - Modifying a Global Variable
main.py
20 20
Explanation
The statement global a informs Python that the variable belongs to the Global Scope.
Now the assignment updates the original Global Variable instead of creating a Local Variable.
Therefore, both statements print 20.
Example 4 - Multiple Functions Using global
main.py
3
Explanation
The Global Variable count is updated every time the function is called.
Since the same Global Variable is modified, the final value becomes 3.
The globals() Function
Python provides the built-in globals() function.
This function returns a Dictionary containing all Global Variables available in the current module.
The Dictionary keys represent variable names, and the values represent the corresponding Global Variable values.
Syntax
main.py
No output captured.
Example 5 - Using globals()
main.py
{'a': 10, 'b': 20, ...}Explanation
The globals() function returns a Dictionary.
Besides user-defined Global Variables, the Dictionary also contains several built-in objects created by Python.
For simplicity, only user-defined variables are shown in the sample output.
Example 6 - Accessing Global Variables Using globals()
main.py
100 200
Explanation
The globals() function returns a Dictionary.
Dictionary indexing can be used to access any Global Variable by its name.
Example 7 - Modifying Global Variable Using globals()
main.py
50
Explanation
Since globals() returns the Global Namespace Dictionary, changing its value updates the original Global Variable.
Difference Between global Keyword and globals()
| global Keyword | globals() Function |
|---|---|
| Used inside a function. | Can be used anywhere. |
| Declares a variable as Global. | Returns the Global Namespace Dictionary. |
| Mainly used to modify Global Variables. | Used to view or access all Global Variables. |
| Keyword. | Built-in Function. |
Real-World Applications
- Maintaining application-wide counters.
- Updating global configuration values.
- Managing shared application state.
- Accessing global settings across multiple functions.
- Debugging by inspecting the Global Namespace.
Summary
| Concept | Description |
|---|---|
global |
Allows modification of Global Variables inside a function. |
globals() |
Returns the Global Namespace Dictionary. |
| Without global | A new Local Variable is created during assignment. |
| With global | The original Global Variable is modified. |
Important Notes
- Reading a Global Variable inside a function does not require the
globalkeyword. - Modifying a Global Variable inside a function requires the
globalkeyword. - Without
global, Python creates a new Local Variable when an assignment is made. globals()returns a Dictionary containing all Global Variables.- Global Variables can be accessed using dictionary indexing on the result of
globals(). globalis a keyword, whereasglobals()is a built-in function.- Excessive use of Global Variables can make programs difficult to maintain, so they should be used carefully.
Introduction to Recursive Functions
In the previous sections, we learned how one function can call another function.
Python also allows a function to call itself.
A function that calls itself is called a Recursive Function.
The process of a function calling itself repeatedly until a specific condition is satisfied is known as Recursion.
Recursion is a powerful programming technique used to solve problems that can be divided into smaller versions of the same problem.
Definition
A Recursive Function is a function that calls itself either directly or indirectly until a terminating condition is reached.
The terminating condition is called the Base Case.
Why Do We Need Recursion?
Many real-world problems are naturally recursive.
Instead of writing complicated loops, recursion provides a cleaner and easier solution.
It is especially useful when solving problems that involve repeated subdivision into smaller sub-problems.
Common examples include:
- Factorial Calculation
- Fibonacci Series
- Tree Traversal
- Directory/File Traversal
- Binary Search
- Tower of Hanoi
How Recursion Works
Every recursive function contains two important parts:
- Base Case
- Recursive Case
The Recursive Case keeps calling the function repeatedly.
The Base Case stops further recursive calls and prevents infinite recursion.
Components of a Recursive Function
| Component | Purpose |
|---|---|
| Base Case | Stops the recursion. |
| Recursive Case | Calls the function again. |
Syntax
main.py
No output captured.
First Recursive Program
main.py
No output captured.
Output
Explanation
The function display() calls itself continuously.
Since there is no Base Case, the recursive calls never stop.
Python keeps creating new function calls until the maximum recursion depth is exceeded.
Finally, Python raises a RecursionError.
Understanding Infinite Recursion
Infinite recursion occurs when a recursive function has no terminating condition.
Every function call creates another function call.
Eventually, Python runs out of available call stack space.
To prevent this situation, every recursive function must include a Base Case.
Example with Base Case
main.py
5 4 3 2 1
Understanding the Program
The function starts with the value 5.
Each recursive call decreases the value of n by 1.
When n becomes 0, the Base Case executes and recursion stops.
Dry Run
| Function Call | Output |
|---|---|
| display(5) | 5 |
| display(4) | 4 |
| display(3) | 3 |
| display(2) | 2 |
| display(1) | 1 |
| display(0) | Stops |
Flow of Recursive Function
| Step | Action |
|---|---|
| 1 | Function is called. |
| 2 | Base Case is checked. |
| 3 | If Base Case is false, the function calls itself. |
| 4 | Each recursive call receives a smaller problem. |
| 5 | When the Base Case becomes true, recursion stops. |
Difference Between Normal Function and Recursive Function
| Normal Function | Recursive Function |
|---|---|
| Does not call itself. | Calls itself. |
| Usually uses loops for repetition. | Uses repeated function calls. |
| Generally easier for simple repetitive tasks. | Better for problems that can be divided into smaller sub-problems. |
Real-World Applications
- Factorial calculation.
- Fibonacci sequence.
- Binary Search.
- Tree Traversal.
- Graph Traversal.
- Directory and File System Traversal.
- Tower of Hanoi.
Quick Summary
| Concept | Description |
|---|---|
| Recursive Function | A function that calls itself. |
| Base Case | Stops recursion. |
| Recursive Case | Calls the function again. |
| Without Base Case | RecursionError occurs. |
| Main Use | Solving recursive problems. |
Important Notes
- A Recursive Function calls itself.
- Every recursive function must contain a Base Case.
- The Base Case prevents infinite recursion.
- If no Base Case exists, Python raises
RecursionError. - Each recursive call should reduce the problem size.
- Recursive functions are widely used for mathematical and tree-based algorithms.
Recursive Program - Factorial of a Number
The Factorial of a positive integer is the product of all positive integers from 1 to that number.
Factorial is represented by the symbol !.
It is one of the most common examples used to understand Recursion because the problem can be divided into smaller versions of itself.
Factorial Formula
The mathematical formula for factorial is:
main.py
No output captured.
Examples
main.py
No output captured.
Recursive Logic
The recursive definition of factorial is:
main.py
No output captured.
Base Case
The recursion must stop when the value becomes 0 or 1.
Both 0! and 1! are equal to 1.
Program - Factorial Using Recursion
main.py
No output captured.
Sample Output
Program Explanation
The function receives a number from the user.
If the number becomes 0, the Base Case executes and returns 1.
Otherwise, the function calls itself with n-1.
Each recursive call multiplies the current number with the factorial of the next smaller number.
Finally, all recursive calls return one by one and the final factorial value is produced.
Step-by-Step Execution for factorial(5)
main.py
No output captured.
Recursive Function Calls
| Function Call | Status |
|---|---|
| factorial(5) | Calls factorial(4) |
| factorial(4) | Calls factorial(3) |
| factorial(3) | Calls factorial(2) |
| factorial(2) | Calls factorial(1) |
| factorial(1) | Calls factorial(0) |
| factorial(0) | Returns 1 (Base Case) |
Call Stack (Function Calling Phase)
main.py
No output captured.
Call Stack (Returning Phase)
main.py
No output captured.
Visual Representation
| Recursive Call | Returned Value |
|---|---|
| factorial(0) | 1 |
| factorial(1) | 1 |
| factorial(2) | 2 |
| factorial(3) | 6 |
| factorial(4) | 24 |
| factorial(5) | 120 |
Dry Run
| Step | Operation |
|---|---|
| 1 | factorial(5) is called. |
| 2 | It calls factorial(4). |
| 3 | Each function keeps calling the next smaller value. |
| 4 | When factorial(0) is reached, 1 is returned. |
| 5 | Each pending function multiplies its value while returning. |
| 6 | The final answer becomes 120. |
Important Points
- Every recursive function must contain a Base Case.
- The Base Case prevents infinite recursion.
- Each recursive call should reduce the problem size.
- The recursive calls are stored in the Call Stack.
- After reaching the Base Case, the Call Stack starts returning values one by one.
- The factorial program is one of the best examples for understanding recursion.
Advantages of Recursive Functions
Recursive functions provide an elegant and efficient solution for many problems that can be divided into smaller sub-problems.
Instead of writing long and complex iterative code, recursion often produces shorter and easier-to-understand programs.
Some important advantages of recursion are listed below.
- Produces shorter and cleaner code.
- Makes programs easier to understand for recursive problems.
- Suitable for mathematical problems such as Factorial and Fibonacci.
- Very useful for Tree Traversal and Graph Traversal.
- Reduces the complexity of solving divide-and-conquer problems.
- Used extensively in searching and sorting algorithms.
- Improves readability for naturally recursive problems.
Disadvantages of Recursive Functions
Although recursion is powerful, it also has some limitations.
Each recursive function call creates a new stack frame in memory.
If recursion continues for many levels, more memory is consumed and the program becomes slower.
- Consumes more memory because of the Call Stack.
- Slower than loops for many simple problems.
- Improper Base Case causes infinite recursion.
- May generate
RecursionError. - Debugging recursive functions is more difficult than loops.
- Not suitable for every programming problem.
When Should We Use Recursion?
Recursion should be used only when it makes the solution simpler and more natural.
Some common situations where recursion is preferred are:
- Factorial Calculation
- Fibonacci Series
- Tree Traversal
- Directory Traversal
- Binary Search
- Depth First Search (DFS)
- Tower of Hanoi
- Merge Sort and Quick Sort
When Should We Avoid Recursion?
Recursion should generally be avoided when:
- A simple loop can solve the problem easily.
- The recursion depth may become very large.
- Memory usage is an important concern.
- Performance is more important than code simplicity.
Recursion vs Loop
| Recursion | Loop |
|---|---|
| Function calls itself. | Repeats statements using loops. |
| Uses Call Stack. | Does not create recursive stack frames. |
| Consumes more memory. | Consumes less memory. |
| Usually slower. | Usually faster. |
| Code is shorter for recursive problems. | Code may become longer for recursive problems. |
| Needs a Base Case. | Needs a Loop Condition. |
| Best for divide-and-conquer problems. | Best for repetitive tasks. |
Normal Function vs Recursive Function
| Normal Function | Recursive Function |
|---|---|
| Does not call itself. | Calls itself. |
| Usually uses loops. | Uses recursive calls. |
| Consumes less memory. | Consumes more memory. |
| Easy to debug. | Comparatively difficult to debug. |
| Suitable for simple iterative tasks. | Suitable for recursive problems. |
Real-World Applications of Recursion
Recursion is widely used in modern software development.
- Binary Search Algorithms
- Tree Traversal (Preorder, Inorder, Postorder)
- Graph Traversal (DFS)
- Merge Sort
- Quick Sort
- File and Directory Traversal
- Artificial Intelligence Search Algorithms
- Dynamic Programming Problems
- Expression Evaluation
- Compiler Design
Complete Chapter Summary
| Topic | Description |
|---|---|
| Recursive Function | A function that calls itself. |
| Base Case | Stops recursion. |
| Recursive Case | Calls the function again. |
| Call Stack | Stores pending recursive function calls. |
| Factorial | Classic example of recursion. |
| Infinite Recursion | Occurs when the Base Case is missing. |
| RecursionError | Raised when recursion exceeds the maximum recursion depth. |
| Advantages | Cleaner code for recursive problems. |
| Disadvantages | Higher memory usage and slower execution. |
| Applications | Trees, Graphs, Sorting, Searching, AI, File Systems. |
Important Interview Questions
- What is a Recursive Function?
- What is the Base Case?
- Why is the Base Case necessary?
- What is Infinite Recursion?
- What is Call Stack?
- Explain the execution of the Factorial Program.
- Differentiate between Recursion and Loop.
- What are the advantages and disadvantages of recursion?
- When should recursion be preferred over loops?
- Explain RecursionError with an example.
Important Notes
- A Recursive Function calls itself.
- Every recursive function must contain a Base Case.
- The Base Case prevents infinite recursion.
- Recursive calls are managed using the Call Stack.
- Each recursive call should reduce the problem size.
- Without a Base Case, Python raises
RecursionError. - Recursion generally consumes more memory than loops.
- Loops are usually faster for simple repetitive tasks.
- Recursion is ideal for divide-and-conquer algorithms.
- Tree Traversal and Graph Traversal are common recursive applications.
Introduction to Lambda (Anonymous) Functions
In the previous sections, we learned how to create functions using the def keyword.
Python also provides another way to create functions called Lambda Functions.
A Lambda Function is a small anonymous function that can be created without using the def keyword.
These functions are generally used when a function is required only for a short period of time.
Because they do not have a function name, they are also called Anonymous Functions.
Definition
A Lambda Function is an anonymous function created using the lambda keyword.
It can have any number of parameters but can contain only one expression.
The value of that expression is automatically returned.
Why Do We Need Lambda Functions?
Sometimes we need a function only once in a program.
Creating a complete function using def for such small tasks increases the amount of code.
Lambda Functions provide a simple and compact way to write these small functions.
They are commonly used with built-in functions like:
map()filter()reduce()sorted()
Characteristics of Lambda Functions
- Created using the
lambdakeyword. - Do not have a function name.
- Also called Anonymous Functions.
- Can accept any number of parameters.
- Can contain only one expression.
- Automatically return the result of the expression.
- Generally used for short and simple operations.
Syntax
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
lambda |
Keyword used to create an anonymous function. |
| arguments | Input parameters for the function. |
| expression | The expression whose result is automatically returned. |
First Lambda Function
main.py
25 100
Explanation
The Lambda Function receives one parameter x.
The expression x * x is evaluated.
The calculated value is automatically returned.
Unlike a normal function, no explicit return statement is required.
Equivalent Normal Function
main.py
25 100
Comparison
Both functions produce the same output.
The Lambda Function requires fewer lines of code.
It is suitable for simple operations.
Example - Addition
main.py
30 150
Example - Multiplication
main.py
30 200
Example - Convert to Uppercase
main.py
PYTHON CODING
Lambda Function Flow
| Step | Action |
|---|---|
| 1 | Arguments are passed to the Lambda Function. |
| 2 | The expression is evaluated. |
| 3 | The result is automatically returned. |
Limitations of Lambda Functions
- Can contain only one expression.
- Cannot contain multiple statements.
- Cannot directly use loops like
fororwhile. - Not suitable for writing complex business logic.
- Mainly used for small operations.
Real-World Applications
- Sorting custom objects.
- Data transformation.
- Filtering collections.
- Data analysis.
- Machine Learning preprocessing.
- Using
map(),filter(), andreduce().
Quick Summary
| Concept | Description |
|---|---|
| Lambda Function | Anonymous function. |
| Keyword | lambda |
| Name | Not required. |
| Statements | Only one expression. |
| Return | Automatic. |
Important Notes
- Lambda Functions are also called Anonymous Functions.
- They are created using the
lambdakeyword. - They can accept any number of parameters.
- Only one expression is allowed inside a Lambda Function.
- The expression result is returned automatically.
- No explicit
returnstatement is required. - Lambda Functions are commonly used with
map(),filter(), andreduce().
Working with Lambda Functions
In the previous section, we learned how to create simple Lambda Functions.
In this section, we will learn how Lambda Functions work with multiple parameters, conditional expressions, and various practical examples.
Since Lambda Functions automatically return the value of a single expression, they are widely used for short calculations.
Lambda Function with Multiple Arguments
A Lambda Function can accept any number of arguments.
All arguments are separated by commas, just like normal function parameters.
Example 1 - Addition
main.py
30 150
Explanation
The Lambda Function accepts two parameters a and b.
The expression a + b is evaluated and the result is automatically returned.
Example 2 - Multiplication
main.py
30 600
Example 3 - Find Maximum
main.py
20 50
Explanation
The Lambda Function uses Python's conditional expression.
If a is greater than b, it returns a; otherwise, it returns b.
Example 4 - Find Minimum
main.py
10 30
Lambda Function Returning Boolean Values
Lambda Functions can also return Boolean values.
This is useful when checking conditions.
Example 5 - Even Number
main.py
True False
Example 6 - Positive Number
main.py
True False
Lambda Function with Three Arguments
main.py
30 90
Lambda Function Returning Strings
main.py
Welcome Rahul Welcome Python
Lambda Function with String Operations
main.py
PYTHON 11
Nested Conditional Expression
main.py
40 90
Flow of Lambda Function
| Step | Description |
|---|---|
| 1 | Arguments are passed to the Lambda Function. |
| 2 | The expression is evaluated. |
| 3 | The result is returned automatically. |
Things to Remember
- Lambda Functions can accept zero, one, or many arguments.
- Only one expression is allowed.
- The expression may contain arithmetic, logical, comparison, or conditional operators.
- The evaluated result is returned automatically.
- Complex business logic should be written using normal functions.
Common Use Cases
- Simple mathematical calculations.
- Conditional expressions.
- Sorting collections.
- Data transformation.
- Filtering records.
- Quick helper functions.
Summary
| Feature | Description |
|---|---|
| Multiple Arguments | Supported. |
| Return Value | Returned automatically. |
| Conditional Expression | Supported. |
| Boolean Result | Supported. |
| String Operations | Supported. |
| Maximum Statements | Only one expression. |
Important Notes
- Lambda Functions automatically return the expression result.
- They can accept any number of parameters.
- Conditional expressions can be used inside Lambda Functions.
- Boolean values can be returned directly.
- Lambda Functions are ideal for short and simple operations.
- Multiple statements are not allowed inside a Lambda Function.
Lambda Function vs Normal Function
Python provides two ways to create functions:
- Normal Functions using the
defkeyword. - Lambda (Anonymous) Functions using the
lambdakeyword.
Both perform the same task of executing reusable code, but they differ in syntax, complexity, and use cases.
Normal Functions are suitable for large programs, whereas Lambda Functions are ideal for short, single-expression operations.
Example 1 - Normal Function
main.py
25 100
Example 2 - Lambda Function
main.py
25 100
Explanation
Both functions produce the same output.
The Lambda Function requires fewer lines of code because it automatically returns the expression result.
For simple operations, Lambda Functions make the code shorter and easier to read.
Normal Function vs Lambda Function
| Normal Function | Lambda Function |
|---|---|
Created using the def keyword. |
Created using the lambda keyword. |
| Has a function name. | Usually anonymous (no function name). |
| Can contain multiple statements. | Can contain only one expression. |
Requires an explicit return statement to return a value. |
Automatically returns the expression result. |
| Suitable for large and complex logic. | Suitable for small and simple operations. |
| Supports loops, conditions, exception handling, and multiple statements. | Cannot directly contain loops, multiple statements, or exception handling. |
| Easier to maintain for complex programs. | Useful for quick, temporary helper functions. |
Advantages of Lambda Functions
- Short and concise syntax.
- Requires fewer lines of code.
- No explicit
returnstatement is needed. - Ideal for one-time or temporary functions.
- Works well with built-in functions like
map(),filter(), andreduce(). - Improves readability for simple operations.
- Commonly used in Data Science and Machine Learning code.
Disadvantages of Lambda Functions
- Only one expression is allowed.
- Cannot contain multiple statements.
- Cannot directly use loops such as
forandwhile. - Not suitable for large business logic.
- Can become difficult to read if the expression is too complex.
- Less suitable for debugging than Normal Functions.
When Should You Use Lambda Functions?
Lambda Functions are recommended when:
- A function is required only once.
- The operation is very small.
- Working with
map(),filter(), orreduce(). - Sorting collections using a custom key.
- Writing short callback functions.
When Should You Use Normal Functions?
Normal Functions are recommended when:
- The logic is complex.
- Multiple statements are required.
- The function needs loops or exception handling.
- The function will be reused many times.
- Better readability and maintainability are required.
Real-World Applications of Lambda Functions
- Sorting objects using custom keys.
- Data filtering.
- Data transformation.
- Machine Learning preprocessing.
- Data Analysis with Pandas.
- GUI callback functions.
- Functional programming.
Complete Chapter Summary
| Topic | Description |
|---|---|
| Lambda Function | An anonymous function created using the lambda keyword. |
| Anonymous Function | A function without a predefined name. |
| Arguments | Can accept any number of arguments. |
| Expression | Only one expression is allowed. |
| Return Value | Automatically returned. |
| Main Uses | map(), filter(), reduce(), sorting, callbacks. |
| Best For | Short and simple functions. |
| Avoid For | Complex business logic. |
Important Interview Questions
- What is a Lambda Function?
- Why is a Lambda Function called an Anonymous Function?
- What is the syntax of a Lambda Function?
- How many expressions are allowed inside a Lambda Function?
- Can Lambda Functions have multiple parameters?
- Differentiate between Normal Functions and Lambda Functions.
- What are the advantages of Lambda Functions?
- What are the disadvantages of Lambda Functions?
- Where are Lambda Functions commonly used?
- Why are Lambda Functions frequently used with
map(),filter(), andreduce()?
Important Notes
- Lambda Functions are anonymous functions.
- They are created using the
lambdakeyword. - They can accept any number of arguments.
- Only one expression is allowed.
- The expression result is returned automatically.
- No explicit
returnstatement is required. - Lambda Functions are ideal for small operations.
- Normal Functions are better for large and reusable code.
- Lambda Functions are widely used in Functional Programming and Data Science.
Introduction to filter() Function
The filter() function is one of Python's built-in functions.
It is used to select elements from an iterable (such as a list, tuple, or set) based on a given condition.
Instead of modifying the original collection, filter() creates a new iterator that contains only the elements that satisfy the specified condition.
In Python, filter() is commonly used together with Lambda Functions to write short and efficient code.
Definition
The filter() function filters elements from an iterable by applying a function to each element.
If the function returns True, the element is included in the result.
If the function returns False, the element is discarded.
Why Do We Need filter()?
Suppose we have a list containing hundreds of numbers.
If we want only the even numbers, we would normally use a loop with an if statement.
The filter() function performs this task in a much shorter and cleaner way.
It helps improve code readability and reduces the amount of code.
Syntax
main.py
No output captured.
Syntax Explanation
| Parameter | Description |
|---|---|
function |
A function that returns either True or False. |
iterable |
The collection whose elements will be filtered. |
Return Value
The filter() function returns a filter object.
This filter object is an iterator.
To display the filtered values, it is usually converted into a list, tuple, or set.
Program 1 - Simple filter() Example
main.py
[25, 30]
Explanation
The Lambda Function checks whether each number is greater than 20.
If the condition is True, the element is selected.
Initially, filter() returns a filter object.
After converting it into a list using list(), the filtered values become visible.
Program 2 - Filtering Even Numbers
main.py
[10, 20, 30, 40]
Explanation
The Lambda Function checks whether the remainder after dividing by 2 is equal to 0.
If the condition is true, the number is included in the result.
Program 3 - Filtering Odd Numbers
main.py
[15, 25, 35]
Program 4 - Using a Normal Function
main.py
[10, 20, 30]
Explanation
Instead of using a Lambda Function, a Normal Function can also be passed to filter().
The function should always return True or False.
How filter() Works
| Element | Condition | Included? |
|---|---|---|
| 10 | True | ✔ Yes |
| 15 | False | ✘ No |
| 20 | True | ✔ Yes |
| 25 | False | ✘ No |
| 30 | True | ✔ Yes |
Flow of filter() Function
| Step | Description |
|---|---|
| 1 | Read one element from the iterable. |
| 2 | Pass the element to the function. |
| 3 | If the function returns True, keep the element. |
| 4 | If the function returns False, discard the element. |
| 5 | Return the filtered iterator. |
Advantages of filter()
- Simple and readable code.
- Reduces the need for loops.
- Works efficiently with Lambda Functions.
- Useful for selecting required data.
- Returns an iterator, making it memory efficient.
Quick Summary
| Concept | Description |
|---|---|
| Function | filter() |
| Purpose | Select elements that satisfy a condition. |
| Returns | Filter Object (Iterator) |
| Common Partner | Lambda Function |
| Output Conversion | list(), tuple(), set() |
Important Notes
filter()is a built-in Python function.- It selects elements based on a condition.
- The supplied function must return
TrueorFalse. - It returns a filter object (iterator).
- Convert the filter object using
list(),tuple(), orset()to view the filtered elements. - It is commonly used with Lambda Functions.
More filter() Examples
In the previous section, we learned the basics of the filter() function.
In this section, we will explore more practical examples using different types of data.
These examples demonstrate how filter() can be used to filter numbers, strings, and other collections efficiently.
Program 1 - Filter Positive Numbers
main.py
[20, 40, 50]
Explanation
The Lambda Function checks whether each number is greater than 0.
Only positive numbers satisfy the condition and are included in the result.
Program 2 - Filter Negative Numbers
main.py
[-10, -30, -60]
Program 3 - Filter Numbers Greater Than 50
main.py
[55, 70, 90]
Program 4 - Filter Numbers Divisible by 5
main.py
[15, 20, 25, 35]
Program 5 - Filter Non-Empty Strings
main.py
['Rahul', 'Amit', 'Neha', 'Python']
Explanation
The Lambda Function checks whether the string is not empty.
Only non-empty strings are included in the final result.
Program 6 - Filter Names Starting with 'A'
main.py
['Amit', 'Ankit', 'Ajay']
Program 7 - Filter String Length Greater Than 5
main.py
['Python', 'JavaScript']
Program 8 - Filter Even Numbers from a Tuple
main.py
(10, 20, 30)
Program 9 - Filter Values from a Set
main.py
{20, 25, 30}Program 10 - Using filter() with None
main.py
[1, 'Python', True, 25]
Explanation
When None is passed as the first argument, filter() automatically removes all falsy values.
Falsy values include:
0FalseNone- Empty String (
"") - Empty List
- Empty Tuple
- Empty Dictionary
Only truthy values remain in the final output.
Real-World Applications
- Filtering active users from a database.
- Selecting students who passed an examination.
- Removing invalid records from datasets.
- Filtering positive transactions.
- Cleaning missing values during data preprocessing.
- Filtering API response data.
- Filtering files based on extensions.
Advantages of filter()
- Produces clean and readable code.
- Reduces the need for manual loops.
- Works efficiently with Lambda Functions.
- Supports all iterable objects.
- Returns an iterator, making it memory efficient.
- Useful for data filtering tasks.
Complete Summary
| Feature | Description |
|---|---|
| Function | filter() |
| Purpose | Select elements that satisfy a condition. |
| Input | Function + Iterable |
| Return Type | Filter Object (Iterator) |
| Works With | List, Tuple, Set, String, etc. |
| Common Partner | Lambda Function |
Important Interview Questions
- What is the purpose of the
filter()function? - What does
filter()return? - Why is
list()commonly used withfilter()? - Can
filter()work with Normal Functions? - Can
filter()work with Lambda Functions? - What happens when
Noneis passed tofilter()? - Which iterable objects are supported by
filter()? - Differentiate between
filter()and loops.
Important Notes
filter()returns only elements that satisfy a condition.- The filtering function must return
TrueorFalse. - It returns a filter object (iterator).
- Use
list(),tuple(), orset()to display the filtered values. filter(None, iterable)removes all falsy values from the iterable.filter()works with all iterable objects such as lists, tuples, sets, and strings.- It is widely used in Data Analysis, Machine Learning, and Functional Programming.
Introduction to map() Function
The map() function is one of Python's built-in functions.
It is used to apply a function to every element of an iterable such as a list, tuple, set, or string.
Unlike filter(), which selects elements based on a condition, map() transforms every element and returns the modified values.
The original iterable remains unchanged because map() creates a new iterator containing the transformed elements.
In Python, map() is commonly used together with Lambda Functions to write concise and efficient code.
Definition
The map() function applies a specified function to each element of an iterable.
The transformed elements are returned as a map object.
Why Do We Need map()?
Suppose we have a list of numbers and want to calculate the square of every number.
Normally, we would use a loop and create another list.
The map() function performs this task in a cleaner and shorter way.
It reduces the amount of code and improves readability.
Syntax
main.py
No output captured.
Syntax Explanation
| Parameter | Description |
|---|---|
function |
The function that will be applied to every element. |
iterable |
The collection whose elements will be transformed. |
Return Value
The map() function returns a map object.
The map object is an iterator.
To display the transformed values, it is generally converted into a list, tuple, or set.
Program 1 - First map() Example
main.py
[2, 4, 6, 8, 10]
Explanation
The Lambda Function multiplies every number by 2.
Initially, map() returns a map object.
Using list(), the transformed values become visible.
Program 2 - Square of Numbers
main.py
[1, 4, 9, 16, 25]
Program 3 - Cube of Numbers
main.py
[1, 8, 27, 64, 125]
Program 4 - Using a Normal Function
main.py
[4, 16, 36, 64]
Explanation
Instead of using a Lambda Function, a Normal Function can also be passed to map().
The function is applied to every element of the iterable one by one.
Program 5 - Convert Strings to Uppercase
main.py
['PYTHON', 'JAVA', 'REACT', 'NODE']
Program 6 - Find Length of Strings
main.py
[6, 4, 5, 10]
How map() Works
| Original Element | Transformation | New Value |
|---|---|---|
| 1 | x × 2 | 2 |
| 2 | x × 2 | 4 |
| 3 | x × 2 | 6 |
| 4 | x × 2 | 8 |
| 5 | x × 2 | 10 |
Flow of map() Function
| Step | Description |
|---|---|
| 1 | Read one element from the iterable. |
| 2 | Pass the element to the function. |
| 3 | Transform the element. |
| 4 | Store the transformed value. |
| 5 | Return a map object. |
Advantages of map()
- Produces clean and concise code.
- Eliminates the need for manual loops.
- Works efficiently with Lambda Functions.
- Does not modify the original iterable.
- Returns an iterator, making it memory efficient.
- Useful for transforming large collections of data.
Quick Summary
| Concept | Description |
|---|---|
| Function | map() |
| Purpose | Transform elements of an iterable. |
| Returns | Map Object (Iterator) |
| Common Partner | Lambda Function |
| Output Conversion | list(), tuple(), set() |
Important Notes
map()is a built-in Python function.- It applies a function to every element of an iterable.
- It returns a map object (iterator).
- The original iterable is not modified.
- Convert the map object using
list(),tuple(), orset()to display the transformed values. - Both Lambda Functions and Normal Functions can be used with
map().
More map() Examples
In the previous section, we learned the basics of the map() function.
In this section, we will explore more practical examples using numbers, strings, and multiple iterables.
These examples demonstrate how map() can efficiently transform data without modifying the original iterable.
Program 1 - Add 10 to Every Number
main.py
[15, 20, 25, 30, 35]
Explanation
The Lambda Function adds 10 to every element.
The transformed values are returned as a new iterator.
Program 2 - Convert Strings to Lowercase
main.py
['python', 'java', 'react', 'node']
Program 3 - Capitalize First Letter
main.py
['Rahul', 'Amit', 'Neha', 'Pooja']
Program 4 - Convert Integers to Strings
main.py
['10', '20', '30', '40']
Explanation
The built-in str() function is passed directly to map().
Each integer is converted into its string representation.
Program 5 - Find Length of Each String
main.py
[5, 7, 4, 9]
Program 6 - Square of Tuple Elements
main.py
(4, 16, 36, 64)
Program 7 - Multiply Elements from Two Lists
main.py
[10, 40, 90, 160]
Explanation
map() can accept multiple iterables.
The Lambda Function receives one element from each iterable at the same position.
The corresponding elements are multiplied together.
Program 8 - Add Elements of Two Lists
main.py
[11, 22, 33]
Program 9 - Convert List of Strings to Integers
main.py
[10, 20, 30, 40]
Program 10 - Remove Extra Spaces
main.py
['Rahul', 'Amit', 'Neha', 'Pooja']
Working with Multiple Iterables
One of the important features of map() is that it can process multiple iterables simultaneously.
The supplied function receives one value from each iterable during every iteration.
If the iterables have different lengths, processing stops when the shortest iterable is exhausted.
Flow of map() with Multiple Iterables
| List 1 | List 2 | Lambda Result |
|---|---|---|
| 1 | 10 | 10 |
| 2 | 20 | 40 |
| 3 | 30 | 90 |
| 4 | 40 | 160 |
Real-World Applications
- Converting data types.
- Formatting user input.
- Cleaning datasets before analysis.
- Performing mathematical calculations.
- Transforming API response data.
- Data preprocessing for Machine Learning.
- Applying the same operation to every record.
Advantages of map()
- Produces concise and readable code.
- Eliminates manual loops.
- Works efficiently with Lambda Functions.
- Supports multiple iterables.
- Returns an iterator, making it memory efficient.
- Does not modify the original iterable.
Complete Summary
| Feature | Description |
|---|---|
| Function | map() |
| Purpose | Transform every element of an iterable. |
| Input | Function + One or More Iterables |
| Return Type | Map Object (Iterator) |
| Supports | Multiple Iterables |
| Common Partner | Lambda Function |
Important Interview Questions
- What is the purpose of the
map()function? - What does
map()return? - Can
map()work with Normal Functions? - Can
map()process multiple iterables? - What happens if multiple iterables have different lengths?
- How is
map()different fromfilter()? - Can built-in functions like
str()andlen()be passed tomap()? - Why is
map()widely used in Data Science?
Important Notes
map()transforms every element of an iterable.- It returns a map object (iterator).
- Use
list(),tuple(), orset()to display the transformed values. - It supports one or more iterables.
- If multiple iterables are supplied, processing stops when the shortest iterable ends.
- Both Lambda Functions and Normal Functions can be used with
map(). map()is widely used in Functional Programming, Data Analysis, and Machine Learning.
Introduction to reduce() Function
The reduce() function is used to reduce an entire iterable into a single value.
Unlike map(), which transforms every element, and filter(), which selects specific elements, reduce() repeatedly combines the elements of an iterable until only one final result remains.
The reduce() function is not a built-in function in Python 3.
It is available inside the functools module.
Definition
The reduce() function repeatedly applies a specified function to the elements of an iterable and produces a single final value.
Each iteration combines two values into one until all elements have been processed.
Why Do We Need reduce()?
Suppose we have a list of numbers.
If we want to calculate the total sum or product of all numbers, we normally use a loop.
The reduce() function performs this operation with very little code.
It is especially useful for cumulative calculations.
Importing reduce()
main.py
No output captured.
Explanation
Since Python 3, reduce() belongs to the functools module.
Therefore, it must be imported before it can be used.
Syntax
main.py
No output captured.
Syntax Explanation
| Parameter | Description |
|---|---|
function |
Function that combines two values. |
iterable |
Collection whose values are processed. |
initializer |
Optional starting value for the reduction. |
Return Value
The reduce() function returns a single value.
This value is the final result after processing all elements of the iterable.
Program 1 - First reduce() Example
main.py
100
Explanation
The Lambda Function adds two values together.
The first two elements are added, then the result is added to the next element.
This process continues until every element has been processed.
The final result is 100.
Step-by-Step Execution
main.py
No output captured.
Program 2 - Product of Numbers
main.py
120
Step-by-Step Execution
main.py
No output captured.
Program 3 - Using a Normal Function
main.py
50
Explanation
Instead of using a Lambda Function, a Normal Function can also be supplied to reduce().
The function always receives two arguments.
The returned value becomes the first argument for the next iteration.
Program 4 - Using an Initializer
main.py
160
Explanation
The initializer provides the starting value.
The reduction begins with 100.
Calculation:
100 + 10 = 110
110 + 20 = 130
130 + 30 = 160
How reduce() Works
| Iteration | Current Values | Result |
|---|---|---|
| 1 | 10, 20 | 30 |
| 2 | 30, 30 | 60 |
| 3 | 60, 40 | 100 |
Flow of reduce() Function
| Step | Description |
|---|---|
| 1 | Take the first two elements. |
| 2 | Apply the supplied function. |
| 3 | Store the returned result. |
| 4 | Combine the result with the next element. |
| 5 | Repeat until all elements are processed. |
| 6 | Return one final value. |
Advantages of reduce()
- Produces clean and compact code.
- Ideal for cumulative calculations.
- Works efficiently with Lambda Functions.
- Returns a single final value.
- Useful for mathematical operations.
Quick Summary
| Concept | Description |
|---|---|
| Function | reduce() |
| Module | functools |
| Purpose | Reduce all elements into one value. |
| Returns | Single Value |
| Common Partner | Lambda Function |
Important Notes
reduce()belongs to thefunctoolsmodule.- It must be imported before use.
- It repeatedly combines iterable elements.
- The supplied function always receives two arguments.
- The final result is a single value.
- An optional initializer can be supplied as the third argument.
- Both Lambda Functions and Normal Functions can be used with
reduce().
More reduce() Examples
In the previous section, we learned the basics of the reduce() function.
In this section, we will solve more practical examples using reduce().
These examples demonstrate how multiple values are repeatedly combined into a single final result.
Program 1 - Find Sum of Numbers
main.py
150
Explanation
The Lambda Function adds two numbers at a time.
The intermediate result becomes the first argument for the next iteration until a single final value remains.
Step-by-Step Execution
main.py
No output captured.
Program 2 - Find Product of Numbers
main.py
120
Step-by-Step Execution
main.py
No output captured.
Program 3 - Find Maximum Number
main.py
80
Explanation
The Lambda Function compares two values.
The larger value is carried forward to the next comparison.
Finally, the largest value is returned.
Program 4 - Find Minimum Number
main.py
15
Program 5 - Concatenate Strings
main.py
Python is Awesome
Program 6 - Find Longest String
main.py
Programming
Program 7 - Sum with Initializer
main.py
160
Explanation
The reduction starts with the initializer value 100.
Then every element of the iterable is added one by one.
Program 8 - Product with Initializer
main.py
240
Step-by-Step Execution
main.py
No output captured.
Real-World Applications of reduce()
- Finding the total sales amount.
- Calculating total marks.
- Finding maximum and minimum values.
- Computing products of numbers.
- String concatenation.
- Financial calculations.
- Data aggregation in Data Science.
- Machine Learning preprocessing.
Advantages of reduce()
- Produces short and readable code.
- Ideal for cumulative calculations.
- Works efficiently with Lambda Functions.
- Returns a single final value.
- Supports an optional initializer.
- Useful in Functional Programming.
Complete Summary
| Feature | Description |
|---|---|
| Function | reduce() |
| Module | functools |
| Purpose | Reduce all iterable elements into one value. |
| Return Type | Single Value |
| Supports Initializer | Yes |
| Common Partner | Lambda Function |
Comparison - filter(), map(), reduce()
| Function | Purpose | Returns |
|---|---|---|
filter() |
Select elements based on a condition. | Filter Object |
map() |
Transform every element. | Map Object |
reduce() |
Combine all elements into one value. | Single Value |
Important Interview Questions
- What is the purpose of
reduce()? - Which module contains the
reduce()function? - What does
reduce()return? - How many arguments does the supplied function receive?
- What is the purpose of the initializer?
- Can Normal Functions be used with
reduce()? - Differentiate between
filter(),map(), andreduce(). - Where is
reduce()commonly used in real-world applications?
Important Notes
reduce()belongs to thefunctoolsmodule.- It reduces an iterable to a single value.
- The supplied function always receives two arguments.
- The result of one iteration becomes the first argument of the next iteration.
- An initializer provides the starting value for the reduction.
- Both Lambda Functions and Normal Functions can be used with
reduce(). reduce()is commonly used for aggregation, mathematical calculations, and functional programming.
Introduction
Python provides three powerful functional programming utilities:
filter()map()reduce()
These functions are commonly used together with Lambda Functions to write short, readable, and efficient code.
Although all three functions work with iterables, each one serves a different purpose.
Quick Overview
| Function | Main Purpose |
|---|---|
filter() |
Select elements that satisfy a condition. |
map() |
Transform every element. |
reduce() |
Combine all elements into a single value. |
Comparison - filter() vs map() vs reduce()
| Feature | filter() | map() | reduce() |
|---|---|---|---|
| Purpose | Select elements | Transform elements | Combine elements |
| Input | Function + Iterable | Function + One or More Iterables | Function + Iterable |
| Output | Filter Object | Map Object | Single Value |
| Works with Lambda | Yes | Yes | Yes |
| Works with Normal Function | Yes | Yes | Yes |
| Returns Iterator | Yes | Yes | No |
| Returns Single Value | No | No | Yes |
| Memory Efficient | Yes | Yes | Yes |
| Main Use | Filtering Data | Data Transformation | Aggregation |
When Should You Use Each Function?
| Situation | Recommended Function |
|---|---|
| Select even numbers | filter() |
| Select students who passed | filter() |
| Convert names to uppercase | map() |
| Calculate square of every number | map() |
| Find total marks | reduce() |
| Find product of numbers | reduce() |
| Find largest value | reduce() |
Advantages
filter()
- Selects only required elements.
- Produces cleaner code.
- Memory efficient.
map()
- Transforms every element.
- Reduces manual loops.
- Supports multiple iterables.
reduce()
- Produces one final result.
- Ideal for aggregation.
- Useful for mathematical calculations.
Disadvantages
| Function | Disadvantages |
|---|---|
filter() |
Only selects elements; cannot transform them. |
map() |
Cannot directly filter unwanted elements. |
reduce() |
May reduce readability for beginners when used with complex expressions. |
Real-World Applications
| Application | Function Used |
|---|---|
| Filter active users | filter() |
| Remove invalid records | filter() |
| Convert currencies | map() |
| Convert temperatures | map() |
| Total sales calculation | reduce() |
| Payroll calculation | reduce() |
| Data preprocessing | All Three |
| Machine Learning | All Three |
Complete Chapter Summary
| Concept | Description |
|---|---|
| filter() | Selects elements that satisfy a condition. |
| map() | Transforms every element. |
| reduce() | Combines iterable elements into one value. |
| Lambda Function | Commonly used with all three functions. |
| Iterator | filter() and map() return iterators. |
| Single Value | reduce() returns one final value. |
| Module | reduce() is available in the functools module. |
Important Interview Questions
- Differentiate between
filter(),map(), andreduce(). - What does each function return?
- Which module contains
reduce()? - Can all three functions work with Lambda Functions?
- Can all three functions work with Normal Functions?
- Which function returns a single value?
- Which function supports multiple iterables?
- When should
filter()be preferred overmap()? - Explain a real-world use case for each function.
- What are the advantages of Functional Programming in Python?
Important Notes
filter()selects elements based on a condition.map()transforms every element.reduce()combines all elements into one final value.filter()andmap()return iterators.reduce()returns a single value.reduce()must be imported from thefunctoolsmodule.- All three functions work with Lambda Functions.
- All three functions also support Normal Functions.
- These functions are widely used in Functional Programming, Data Analysis, Artificial Intelligence, and Machine Learning.
Introduction to Generator Functions
In Python, a Generator Function is a special type of function that generates values one at a time instead of returning all values at once.
A Normal Function uses the return statement to return a value and terminate the function.
A Generator Function uses the yield keyword to produce a value and temporarily pause its execution.
When the Generator Function is called again, it continues execution from the point where it was previously paused.
This makes Generator Functions very useful when working with large amounts of data because they generate values only when required.
What is a Generator Function?
A Generator Function is a function that uses the yield keyword instead of the normal return statement to produce a sequence of values.
When a Generator Function is called, it does not immediately execute the complete function.
Instead, it returns a special object called a Generator Object.
The values from the Generator Object can be retrieved one at a time.
Why Do We Need Generator Functions?
Suppose we need to process millions of records.
If we store all records inside a list, the complete list must be stored in memory.
This can consume a large amount of memory.
A Generator Function solves this problem by generating one value at a time.
Therefore, Generator Functions are useful when:
- Working with large datasets.
- Reading large files.
- Generating large sequences of numbers.
- Processing streaming data.
- Reducing memory consumption.
- Generating values only when they are required.
The yield Keyword
The yield keyword is the most important part of a Generator Function.
It is similar to the return statement because both can send a value back to the caller.
However, there is an important difference.
The return statement terminates the function completely.
The yield statement pauses the function and saves its current state.
When the next value is requested, execution continues from the statement immediately after the previous yield.
Syntax of Generator Function
main.py
No output captured.
First Generator Function
main.py
No output captured.
Explanation
The function display() contains three yield statements.
Because the function contains yield, Python automatically treats it as a Generator Function.
When display() is called, the function does not return all three values immediately.
Instead, it returns a Generator Object.
The exact memory address displayed in the Generator Object may be different each time the program runs.
Generator Object
A Generator Object represents the sequence of values produced by a Generator Function.
The Generator Object is also an iterator.
Therefore, we can retrieve values from it using:
- The
next()function. - A
forloop.
Generator values are produced only when requested. This behaviour is known as Lazy Evaluation.
Using next() with Generator
main.py
10 20 30
Explanation of next()
The first call to next(result) starts the Generator Function.
Execution continues until the first yield statement is reached.
The value 10 is produced and the function pauses.
The second call to next(result) continues execution from the previous position.
The value 20 is produced and the function pauses again.
The third call produces 30.
Step-by-Step Execution
| Function Call | Action | Result |
|---|---|---|
display() |
Creates Generator Object | No value generated yet |
First next() |
Executes until first yield |
10 |
Second next() |
Continues until second yield |
20 |
Third next() |
Continues until third yield |
30 |
What Happens After All Values Are Generated?
After all values have been generated, calling next() again raises a StopIteration exception.
Example - StopIteration
main.py
10 20 StopIteration
Explanation
The Generator Function contains only two yield statements.
The first two calls to next() return 10 and 20.
After that, no more values are available.
Therefore, the third call to next() raises StopIteration.
Using Generator with for Loop
main.py
10 20 30
Explanation
A for loop automatically retrieves values from the Generator Object one at a time.
It internally handles the StopIteration exception.
Therefore, using a for loop is often easier than manually calling next().
Normal Function vs Generator Function
| Normal Function | Generator Function |
|---|---|
Uses return. |
Uses yield. |
| Returns a value and terminates. | Produces a value and pauses. |
| Does not preserve execution state after returning. | Preserves execution state between yields. |
| Normally executes when called. | Calling it creates a Generator Object; execution starts when iteration begins. |
| Usually returns the complete result. | Generates values one at a time. |
| May require more memory when returning large collections. | Memory efficient for large sequences. |
return vs yield
| return | yield |
|---|---|
| Used in Normal Functions. | Used in Generator Functions. |
| Terminates the function. | Pauses the function. |
| Returns a value directly. | Produces a value when requested. |
| Function state is not resumed after returning. | Function state is preserved and execution can continue. |
How Generator Function Works
| Step | Description |
|---|---|
| 1 | A Generator Function is defined using one or more yield statements. |
| 2 | Calling the function creates a Generator Object. |
| 3 | The first value is requested using next() or iteration. |
| 4 | The function executes until it reaches yield. |
| 5 | The value is produced and execution pauses. |
| 6 | The next request resumes execution from the previous position. |
| 7 | When the function finishes, iteration stops. |
Advantages of Generator Functions
- Memory efficient.
- Generates values only when required.
- Useful for processing large datasets.
- Suitable for large or potentially infinite sequences.
- Supports lazy evaluation.
- Preserves the function state between values.
Quick Summary
| Concept | Description |
|---|---|
| Generator Function | A special function that generates values one at a time. |
| Keyword | yield |
| Return Type | Generator Object |
next() |
Retrieves the next generated value. |
| Lazy Evaluation | Values are generated only when requested. |
| StopIteration | Indicates that no more values are available. |
| Main Advantage | Memory efficiency. |
Important Notes
- A Generator Function uses the
yieldkeyword. - Calling a Generator Function returns a Generator Object.
- The function body begins execution when iteration starts, such as with
next()or aforloop. yieldpauses execution and preserves the current state.- The next request resumes execution from where it was paused.
- Generators produce values one at a time.
- Generators support lazy evaluation.
- Calling
next()after all values are exhausted raisesStopIteration. - A
forloop automatically handlesStopIteration. - Generators are useful when working with large amounts of data.
Working with Generator Functions
In the previous section, we learned the basics of Generator Functions and the yield keyword.
In this section, we will learn how to work with Generator Functions using multiple yield statements, the next() function, for loops, parameters, and different number sequences.
Generator Functions generate values one at a time and preserve their execution state between each generated value.
Multiple yield Statements
A Generator Function can contain multiple yield statements.
Each yield produces one value and temporarily pauses the function.
When the next value is requested, execution continues from the statement immediately after the previous yield.
Program 1 - Multiple yield Statements
main.py
10 20 30 40
Explanation
The function contains four yield statements.
The first call to next() produces 10.
The second call continues from the previous position and produces 20.
The same process continues until all values are generated.
Program 2 - Understanding Pause and Resume
main.py
Start 10 After First Yield 20 After Second Yield 30
Explanation
When the first next() is called, the function starts execution.
It prints Start and reaches yield 10.
The value 10 is produced and the function pauses.
When the second next() is called, execution resumes after yield 10.
It prints After First Yield and produces 20.
The third next() resumes the function again and produces 30.
Using Generator Function with for Loop
A Generator Object is iterable.
Therefore, it can be directly used with a for loop.
The for loop automatically requests each value and stops when the Generator is exhausted.
Program 3 - Generator with for Loop
main.py
10 20 30 40
Explanation
The for loop automatically retrieves each value from the Generator.
There is no need to manually call next().
When all values are generated, the loop automatically stops.
Generator Function with Parameters
Just like Normal Functions, Generator Functions can also accept parameters.
The parameter values can be used to control which values the Generator produces.
Program 4 - Generator with Parameter
main.py
1 2 3 4 5
Explanation
The Generator Function receives n as a parameter.
The variable i starts from 1.
Each iteration produces the current value of i.
After producing the value, the function pauses.
When the next value is requested, execution resumes and i is increased by 1.
Program 5 - Generate Even Numbers
main.py
2 4 6 8 10
Explanation
The Generator starts with 2.
After every yield, the value is increased by 2.
Therefore, only even numbers are generated.
Program 6 - Generate Odd Numbers
main.py
1 3 5 7 9
Program 7 - Generate Squares
main.py
1 4 9 16 25
Explanation
The Generator calculates the square of each number.
Instead of creating and storing a complete list of squares, each square is generated only when required.
Program 8 - Generate Countdown
main.py
5 4 3 2 1
Explanation
The Generator starts from the given number.
After producing each value, the number is decreased by 1.
The process continues until the value becomes 0.
Program 9 - Generator Using range()
main.py
1 2 3 4 5
Program 10 - Convert Generator Values to List
main.py
[10, 20, 30, 40]
Explanation
A Generator Object can be converted into a list using list().
However, converting a Generator into a list generates and stores all values in memory.
Therefore, the main memory-saving advantage of the Generator is reduced when all generated values are converted into a list.
Generator Objects Can Be Exhausted
A Generator Object produces each value only once.
After all values have been consumed, the same Generator Object cannot automatically start again.
To iterate again, a new Generator Object must normally be created by calling the Generator Function again.
Program 11 - Generator Exhaustion
main.py
[10, 20, 30] []
Explanation
The first list(result) consumes all values from the Generator Object.
After that, the Generator is exhausted.
Therefore, the second list(result) returns an empty list.
Creating a New Generator Object
main.py
[10, 20, 30] [10, 20, 30]
Explanation
Each call to numbers() creates a new and independent Generator Object.
Therefore, both Generator Objects can produce the complete sequence separately.
Program 12 - Fibonacci Sequence Using Generator
main.py
0 1 1 2 3 5 8 13 21 34
Explanation
The Generator produces Fibonacci numbers one at a time.
The variables a and b store the current and next Fibonacci values.
After each yield, the Generator preserves these variable values.
When execution resumes, the next Fibonacci number is calculated.
This approach is useful because a complete list of Fibonacci numbers does not need to be created before processing begins.
How State is Preserved
| Generator Feature | Description |
|---|---|
| Local Variables | Their values are preserved between yield statements. |
| Execution Position | The position where the function paused is remembered. |
| Next Request | Execution resumes from the previous position. |
| Completion | The Generator becomes exhausted after the function finishes. |
Practical Applications of Generator Functions
- Generating large number sequences.
- Reading large files line by line.
- Processing database records.
- Handling streaming data.
- Generating Fibonacci sequences.
- Creating custom iterators.
- Processing API data in batches.
- Working with large datasets.
Advantages of Working with Generators
- Values are generated only when required.
- Memory consumption is reduced.
- The execution state is automatically preserved.
- Large sequences can be processed efficiently.
- Generators work directly with
forloops. - Generator code can be simpler than creating custom iterator classes.
Quick Summary
| Concept | Description |
|---|---|
| Multiple yield | A Generator Function can produce multiple values. |
| next() | Retrieves one value at a time. |
| for Loop | Automatically iterates through Generator values. |
| Parameters | Generator Functions can accept parameters. |
| State Preservation | Local variables and execution position are preserved. |
| Generator Exhaustion | A Generator Object cannot produce values again after it is exhausted. |
| Lazy Evaluation | Values are generated only when requested. |
Important Notes
- A Generator Function can contain multiple
yieldstatements. - Each
yieldpauses execution and produces one value. - The next request resumes execution from the previous position.
- Generator Functions can accept parameters.
- A
forloop automatically handles Generator iteration. - Local variables preserve their values between
yieldstatements. - A Generator Object is exhausted after all its values are consumed.
- To process the sequence again, create a new Generator Object.
- Converting a Generator to a list stores all generated values in memory.
- Generators are especially useful for large datasets and sequences.
Introduction to Generator Expressions
In the previous sections, we learned how to create Generator Functions using the yield keyword.
Python also provides a shorter and simpler way to create generators called a Generator Expression.
A Generator Expression creates a Generator Object without defining a complete Generator Function.
Generator Expressions are similar to List Comprehensions, but they use parentheses () instead of square brackets [].
Like Generator Functions, Generator Expressions generate values one at a time using lazy evaluation.
What is a Generator Expression?
A Generator Expression is a compact way to create a Generator Object using a single expression.
It does not generate and store all values immediately.
Instead, each value is generated only when it is requested.
This makes Generator Expressions useful when working with large sequences of data.
Syntax
main.py
No output captured.
Syntax Explanation
| Part | Description |
|---|---|
expression |
The operation performed on each element. |
item |
The variable representing each element of the iterable. |
iterable |
The sequence or collection being processed. |
() |
Parentheses are used to create a Generator Expression. |
First Generator Expression
main.py
at 0x...>
Explanation
The expression creates a Generator Object.
The values from 1 to 5 are not immediately stored in memory as a complete collection.
Instead, they are generated one at a time when requested.
The exact memory address shown in the Generator Object may be different each time the program runs.
Using next() with Generator Expression
main.py
1 2 3 4 5
Explanation
Each call to next() retrieves one value from the Generator Expression.
The Generator remembers its current position.
The next call continues from where the previous call stopped.
After all values are consumed, another call to next() raises StopIteration.
Using Generator Expression with for Loop
main.py
1 2 3 4 5
Explanation
A Generator Expression can be directly used with a for loop.
The loop retrieves one value at a time.
It automatically stops when the Generator is exhausted.
Program 1 - Generate Squares
main.py
1 4 9 16 25
Explanation
The expression x ** 2 calculates the square of each number.
Each square is generated only when the for loop requests it.
Program 2 - Generate Cubes
main.py
[1, 8, 27, 64, 125]
Explanation
The Generator Expression produces the cube of each number.
The list() function consumes the Generator and stores all generated values in a list.
Generator Expression with Condition
A Generator Expression can include an if condition.
The condition determines which elements should be generated.
Program 3 - Generate Even Numbers
main.py
[2, 4, 6, 8, 10]
Program 4 - Generate Odd Numbers
main.py
[1, 3, 5, 7, 9]
Program 5 - Generate Numbers Greater Than 20
main.py
[25, 30, 35]
Generator Expression with String Data
main.py
['RAHUL', 'AMIT', 'NEHA', 'POOJA']
Generator Expression with String Condition
main.py
['Python', 'JavaScript']
List Comprehension
main.py
[1, 4, 9, 16, 25]
Equivalent Generator Expression
main.py
at 0x...> [1, 4, 9, 16, 25]
List Comprehension vs Generator Expression
| List Comprehension | Generator Expression |
|---|---|
Uses square brackets []. |
Uses parentheses (). |
| Creates a List. | Creates a Generator Object. |
| Generates all values immediately. | Generates values only when requested. |
| Stores all values in memory. | Produces values one at a time. |
| Suitable for smaller collections. | Suitable for large sequences. |
| Values can be accessed repeatedly. | Values are consumed during iteration. |
| Supports indexing. | Does not support direct indexing. |
Memory Efficiency
The main advantage of Generator Expressions is memory efficiency.
A List Comprehension creates all values and stores them in memory immediately.
A Generator Expression creates values only when they are requested.
For a small collection, the difference may not be noticeable.
However, when processing millions of values, Generator Expressions can significantly reduce memory usage.
Example - Large Sequence
main.py
0 1 4
Explanation
The Generator Expression represents one million square values.
However, all one million values are not created and stored at once.
Only the requested values are generated.
This is why Generator Expressions are useful for processing large sequences.
Generator Expression Can Be Exhausted
main.py
[1, 2, 3] []
Explanation
The first list(numbers) consumes all values from the Generator.
After that, the Generator Object is exhausted.
Therefore, the second conversion produces an empty list.
To generate the sequence again, a new Generator Expression must be created.
Using sum() with Generator Expression
main.py
15
Explanation
The Generator Expression produces numbers from 1 to 5 one at a time.
The sum() function consumes these generated values and calculates the total.
When a Generator Expression is passed as the only argument to a function, an additional pair of parentheses is not required.
Using max() with Generator Expression
main.py
25
Using min() with Generator Expression
main.py
1
Generator Function vs Generator Expression
| Generator Function | Generator Expression |
|---|---|
Defined using def. |
Created using expression syntax. |
Uses the yield keyword. |
Does not explicitly use yield. |
| Can contain multiple statements. | Contains a single expression. |
| Suitable for complex generator logic. | Suitable for simple generator logic. |
| Returns a Generator Object. | Creates a Generator Object. |
| Supports lazy evaluation. | Supports lazy evaluation. |
Advantages of Generator Expressions
- Short and concise syntax.
- Memory efficient.
- Supports lazy evaluation.
- Useful for processing large sequences.
- Works directly with functions such as
sum(),min(), andmax(). - Does not require defining a separate Generator Function for simple operations.
Limitations of Generator Expressions
- Values are consumed only once.
- Does not support direct indexing.
- Not suitable for complex multi-statement logic.
- A new Generator Expression must be created after the previous Generator is exhausted.
- Converting the complete Generator into a list removes its main memory-saving advantage.
Real-World Applications
- Processing large datasets.
- Reading and transforming large data streams.
- Performing calculations on large number sequences.
- Data preprocessing.
- Filtering large collections.
- Creating memory-efficient data pipelines.
- Working with large files and database records.
Quick Summary
| Concept | Description |
|---|---|
| Generator Expression | A compact way to create a Generator Object. |
| Syntax | (expression for item in iterable) |
| Brackets | Uses parentheses (). |
| Evaluation | Lazy Evaluation |
| Memory Usage | Memory efficient. |
| Value Generation | One value at a time. |
| Direct Indexing | Not supported. |
| Main Use | Processing large sequences efficiently. |
Important Notes
- A Generator Expression is a short way to create a Generator Object.
- It uses parentheses
()instead of square brackets[]. - Values are generated only when requested.
- Generator Expressions support lazy evaluation.
- They are more memory efficient than List Comprehensions for large sequences.
- Generator values can be retrieved using
next()or aforloop. - A Generator Expression can include conditions.
- A Generator Object becomes exhausted after all values are consumed.
- Generator Expressions do not support direct indexing.
- They are suitable for simple generator logic, while Generator Functions are better for complex logic.
Generator Functions - Comparison, Summary, and Quiz
In the previous sections, we learned about Generator Functions, the yield keyword, Generator Objects, the next() function, and Generator Expressions.
In this section, we will compare Generator Functions with Normal Functions, Lists, and Generator Expressions.
We will also review the advantages, limitations, real-world applications, and important concepts related to Generators.
Normal Function vs Generator Function
| Feature | Normal Function | Generator Function |
|---|---|---|
| Main Keyword | return |
yield |
| Execution | Normally executes when called. | Calling it creates a Generator Object; execution begins when iteration starts. |
| Function State | Execution is not resumed after return. |
Execution state is preserved between yield statements. |
| Value Generation | Returns a result directly. | Produces values one at a time. |
| Function Completion | return terminates the function. |
yield pauses the function temporarily. |
| Memory Usage | May use more memory when returning large collections. | Memory efficient for large sequences. |
| Lazy Evaluation | Not automatically used. | Yes |
| Return Object | Depends on the returned value. | Generator Object |
Example - Normal Function
main.py
[10, 20, 30]
Example - Generator Function
main.py
10 20 30
Explanation
The Normal Function creates and returns the complete list.
The Generator Function produces one value at a time.
For very large sequences, generating values one at a time can reduce memory consumption.
Generator vs List
| Feature | List | Generator |
|---|---|---|
| Value Storage | Stores all values in memory. | Generates values when requested. |
| Evaluation | Eager Evaluation | Lazy Evaluation |
| Memory Usage | Can be high for large collections. | Usually lower for large sequences. |
| Indexing | Supported | Not supported directly |
| Repeated Iteration | Can normally be iterated multiple times. | A Generator Object is consumed during iteration. |
| Length | len() is supported. |
len() is not directly supported. |
| Best For | Small or reusable collections. | Large or streamed sequences. |
Example - List vs Generator
main.py
[1, 4, 9, 16, 25] at 0x...>
Explanation
The List Comprehension immediately creates and stores all square values.
The Generator Expression creates a Generator Object.
The Generator values are produced only when they are requested.
Generator Function vs Generator Expression
| Feature | Generator Function | Generator Expression |
|---|---|---|
| Creation | Created using def. |
Created using expression syntax. |
| Keyword | Uses yield. |
Does not explicitly use yield. |
| Syntax | Uses a complete function definition. | Uses parentheses (). |
| Logic | Supports complex multi-statement logic. | Best for simple expressions. |
| Return | Returns a Generator Object when called. | Creates a Generator Object directly. |
| Lazy Evaluation | Yes | Yes |
| Memory Efficient | Yes | Yes |
| Best Use | Complex generator logic. | Simple and concise generator logic. |
Example - Generator Function
main.py
1 4 9 16 25
Equivalent Generator Expression
main.py
1 4 9 16 25
Generator Function vs Generator Expression - When to Use
| Situation | Recommended Approach |
|---|---|
| Simple transformation | Generator Expression |
| Simple filtering | Generator Expression |
| Multiple statements | Generator Function |
| Complex conditions | Generator Function |
Multiple yield points |
Generator Function |
| Short one-line generation logic | Generator Expression |
return vs yield
| Feature | return | yield |
|---|---|---|
| Used In | Normal Functions | Generator Functions |
| Function Behaviour | Terminates the function. | Pauses the function. |
| State Preservation | Function does not resume after returning. | Execution state is preserved. |
| Next Execution | A new function call starts execution again. | The next iteration resumes from the previous position. |
| Main Purpose | Return a result. | Produce a sequence lazily. |
Generator Object and Iterator
A Generator Object is a type of iterator.
It produces one value at a time and remembers its current execution state.
Generator values can be retrieved using:
next()- A
forloop - Functions that consume iterables such as
sum(),list(),tuple(),min(), andmax()
Once all values have been consumed, the Generator Object becomes exhausted.
Generator Exhaustion
main.py
[1, 2, 3] []
Explanation
The first list(numbers) consumes all values from the Generator.
The Generator is now exhausted.
Therefore, the second list(numbers) returns an empty list.
To iterate through the sequence again, a new Generator Object must be created.
Lazy Evaluation
Lazy Evaluation means that a value is generated only when it is required.
Generators do not normally calculate and store the complete sequence in advance.
This behaviour is one of the main reasons Generators are useful when working with large datasets and sequences.
Example - Lazy Evaluation
main.py
Generating 1 1 Doing Other Work Generating 2 2
Explanation
Only the requested values are generated.
The third value is not generated because the Generator is not asked for another value.
This demonstrates the lazy behaviour of Generator Functions.
Advantages of Generator Functions
- Memory efficient for large sequences.
- Values are generated only when required.
- Supports lazy evaluation.
- Preserves local variables and execution state.
- Can represent very large sequences without storing every value at once.
- Useful for streaming data.
- Works naturally with
forloops. - Can simplify the creation of custom iterators.
Limitations of Generator Functions
- Generator Objects are consumed during iteration.
- They do not support direct indexing.
- Their length cannot normally be obtained directly using
len(). - Values that have already been consumed cannot be accessed again from the same Generator Object.
- A new Generator Object must be created if the sequence needs to be processed again.
- Generators may be less convenient when random access to elements is required.
- Debugging complex Generator logic may be more difficult for beginners.
When Should You Use Generators?
Generators are especially useful when:
- The dataset is very large.
- You do not need all values at the same time.
- Values can be processed one by one.
- You are reading a large file.
- You are processing streamed data.
- You are generating a large sequence.
- You want to reduce memory consumption.
- You need to create a data-processing pipeline.
When Should You Use a List Instead?
A List may be more suitable when:
- You need direct indexing.
- You need to access the same values repeatedly.
- You need to modify individual elements.
- You need to know the collection length immediately.
- The collection is small enough to store comfortably in memory.
Real-World Applications of Generators
- Reading large files line by line.
- Processing large datasets.
- Handling database query results.
- Processing API responses in batches.
- Streaming data processing.
- Log file processing.
- Generating Fibonacci sequences.
- Generating large mathematical sequences.
- Creating data pipelines.
- Data preprocessing.
Complete Generator Functions Summary
| Concept | Description |
|---|---|
| Generator Function | A special function that produces values one at a time. |
| yield | Produces a value and pauses function execution. |
| Generator Object | An iterator returned by calling a Generator Function. |
| next() | Retrieves the next generated value. |
| for Loop | Automatically iterates over Generator values. |
| StopIteration | Indicates that the Generator has no more values. |
| Lazy Evaluation | Generates values only when they are requested. |
| State Preservation | Local variables and execution position are preserved between yields. |
| Generator Expression | A compact way to create a Generator Object. |
| Generator Expression Syntax | (expression for item in iterable) |
| Generator Exhaustion | A Generator Object cannot automatically restart after all values are consumed. |
| Main Advantage | Memory-efficient processing of large sequences. |
Generator Functions - Complete Flow
| Step | Description |
|---|---|
| 1 | Define a Generator Function using yield. |
| 2 | Call the function to create a Generator Object. |
| 3 | Request a value using next() or iteration. |
| 4 | The function executes until it reaches yield. |
| 5 | The value is produced and the function pauses. |
| 6 | The execution state is preserved. |
| 7 | The next request resumes execution. |
| 8 | The process continues until the function finishes. |
| 9 | The Generator becomes exhausted. |
Important Interview Questions
- What is a Generator Function in Python?
- What is the purpose of the
yieldkeyword? - What is the difference between
returnandyield? - What does a Generator Function return when called?
- What is a Generator Object?
- How does the
next()function work with a Generator? - What is
StopIteration? - What is Lazy Evaluation?
- How does a Generator preserve its execution state?
- What happens when a Generator Object is exhausted?
- What is a Generator Expression?
- What is the difference between a Generator Function and a Generator Expression?
- What is the difference between a List Comprehension and a Generator Expression?
- Why are Generators memory efficient?
- Can a Generator Object be reused after it is exhausted?
- Do Generators support direct indexing?
- When should you use a Generator instead of a List?
- What are some real-world applications of Generators?
Important Notes
- Generator Functions use the
yieldkeyword. - Calling a Generator Function creates a Generator Object.
- The function body begins execution when the Generator is iterated.
yieldproduces a value and pauses execution.- The Generator preserves its local variables and execution position.
next()retrieves one value at a time.- A
forloop automatically handles Generator iteration andStopIteration. - Generators use lazy evaluation.
- Generator Objects are consumed during iteration.
- An exhausted Generator Object does not automatically restart.
- Generator Expressions provide a concise way to create Generator Objects.
- Generator Expressions use parentheses
(). - Generators do not support direct indexing.
- Lists are more suitable when repeated access and indexing are required.
- Generators are especially useful for large datasets, streams, files, and sequences.