Logo OnlineCBT
PYTHON Tutorial
PYTHON · LESSON 15

Functions and Return Values

Package reusable behaviour into focused functions with clear inputs, outputs and documentation.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive
Updated: 26 Jul 2026

Lesson 15: Functions and Return Values

1. Introduction to Modular Programming and Functions

As software applications grow in complexity, writing code sequentially in a single long file becomes inefficient, difficult to debug, and highly error-prone. Repeating identical logic across multiple parts of a program violates a primary rule of software design: DRY (Don't Repeat Yourself).

The solution is Modular Programming using Functions. A function is a self-contained, named block of reusable code designed to perform a specific logical task. Functions accept input data, process that data internally, and optionally pass processed results back to the caller.


2. Defining and Invoking Functions in Python

1. The `def` Keyword and Function Signature

In Python, custom functions are created using the def keyword (short for define), followed by the function identifier name, parentheses () for parameter declarations, and a colon :.

# General Syntax Structure of a Function Definition:
def function_name(parameter_1, parameter_2):
    """Optional Docstring: Explains what the function does."""
    # Indented block of function statements
    executable_code
    return calculated_value
    
Definition vs Invocation: Defining a function with def merely loads its instructions into memory—it does NOT execute the code. To run the function, you must **call or invoke** it by appending parentheses to its identifier: function_name().
BASIC_FUNCTION_DEFINITION.PY
# Defining a simple function
def display_welcome_banner():
    """Prints a standard system header banner."""
    print("=" * 40)
    print("  ENTERPRISE DATA PROCESSING SYSTEM")
    print("=" * 40)

# Invoking (calling) the function multiple times
display_welcome_banner()
print("System running diagnostics...")
display_welcome_banner()
OUTPUT
========================================
  ENTERPRISE DATA PROCESSING SYSTEM
========================================
System running diagnostics...
========================================
  ENTERPRISE DATA PROCESSING SYSTEM
========================================

3. Function Inputs: Basic Parameters and Arguments

Functions become significantly more versatile when they accept external dynamic data through **Parameters**.

  • Parameter: The variable name declared inside the function's header definition parenthesis (e.g., def greet(user_name):).
  • Argument: The actual concrete value passed to the function when calling it (e.g., greet("Alice")).
FUNCTION_WITH_PARAMETERS.PY
def calculate_rectangle_area(width, height):
    """Calculates area given numerical width and height."""
    area = width * height
    print(f"Rectangle Dimensions: {width}x{height} -> Area: {area}")

# Calling function with different positional arguments
calculate_rectangle_area(10, 5)
calculate_rectangle_area(7.5, 3.2)
OUTPUT
Rectangle Dimensions: 10x5 -> Area: 50
Rectangle Dimensions: 7.5x3.2 -> Area: 24.0

4. Function Outputs: The `return` Statement

Instead of merely printing output to the terminal console, production functions process data and pass computed values back to the main program using the return statement.

1. Mechanics of `return`

  1. When Python reaches a return statement inside a function, it **immediately exits the function**, ignoring any statements below it.
  2. It sends the calculated expression value back to the line where the function was called.
  3. If a function reaches its end without encountering an explicit return statement, it automatically returns the default singleton None.
RETURN_VALUE_DEMO.PY
def compute_net_salary(base_salary, bonus, tax_rate):
    """Computes final net salary after taxes."""
    gross = base_salary + bonus
    tax_deduction = gross * tax_rate
    net_pay = gross - tax_deduction
    return net_pay  # Passing result back to caller

# Receiving returned value into a variable
paycheck = compute_net_salary(50000.0, 5000.0, 0.18)
print(f"Final Payable Net Amount: ${paycheck:,.2f}")

# Using returned value directly inside arithmetic expressions
total_payroll = compute_net_salary(40000, 2000, 0.15) + compute_net_salary(60000, 8000, 0.20)
print(f"Combined Payroll Expense: ${total_payroll:,.2f}")
OUTPUT
Final Payable Net Amount: $45,100.00
Combined Payroll Expense: $90,100.00

2. Multiple Return Values (Tuple Unpacking)

A Python function can return multiple values simultaneously by separating them with commas. Internally, Python packs these multiple returned values into a single Tuple, which can be unpacked immediately by the calling code.

MULTIPLE_RETURNS_DEMO.PY
def analyze_sales_figures(revenue, cost):
    """Returns gross profit, profit margin percentage, and profitability status."""
    profit = revenue - cost
    margin = (profit / revenue) if revenue > 0 else 0.0
    is_profitable = profit > 0
    return profit, margin, is_profitable  # Returns a 3-element tuple

# Unpacking multiple returned values into distinct variables
net_profit, margin_pct, status = analyze_sales_figures(150000, 90000)

print(f"Net Profit   : ${net_profit:,.2f}")
print(f"Profit Margin: {margin_pct:.1%}")
print(f"Is Profitable: {status}")
OUTPUT
Net Profit   : $60,000.00
Profit Margin: 40.0%
Is Profitable: True

5. Combining Functions with `match-case` Structural Pattern Matching

Building clean modular architecture involves writing small pure functions that handle business logic, combined with match-case pattern dispatchers to route actions dynamically.

FUNCTION_MATCH_CASE_INTEGRATION.PY
def process_payment(payment_request):
    """
    Processes transaction commands using Structural Pattern Matching inside a function.
    Demonstrates processing list/tuple payloads dynamically.
    """
    match payment_request:
        case ["CREDIT_CARD", card_num, amount] if len(card_num) == 16:
            masked_card = "****-****-****-" + card_num[-4:]
            return f"APPROVED: Paid ${amount:.2f} using Credit Card ({masked_card})"
            
        case ["CREDIT_CARD", card_num, _]:
            return "REJECTED: Credit Card number must be exactly 16 digits."
            
        case ["UPI", upi_id, amount] if "@" in upi_id:
            return f"APPROVED: Paid ${amount:.2f} via UPI ID ({upi_id})"
            
        case ["CASH", amount]:
            return f"APPROVED: Cash on Delivery of ${amount:.2f} recorded."
            
        case _:
            return "ERROR: Payment method or request format invalid."

# Testing the function with structured data requests
requests = [
    ["CREDIT_CARD", "1234567890123456", 299.99],
    ["CREDIT_CARD", "9999", 50.00],
    ["UPI", "user@okbank", 120.00],
    ["CASH", 45.00],
    ["UNKNOWN"]
]

for req in requests:
    result = process_payment(req)
    print(result)
OUTPUT
APPROVED: Paid $299.99 using Credit Card (****-****-****-3456)
REJECTED: Credit Card number must be exactly 16 digits.
APPROVED: Paid $120.00 via UPI ID (user@okbank)
APPROVED: Cash on Delivery of $45.00 recorded.
ERROR: Payment method or request format invalid.

6. Early Returns and Guard Clauses Pattern

A Guard Clause is an early conditional return statement placed at the top of a function that checks for invalid inputs, special boundary cases, or error states, exiting early. This eliminates deep if-else nesting levels.

GUARD_CLAUSE_PATTERN.PY
# Unpythonic Deeply Nested Function:
def divide_bad(a, b):
    if b != 0:
        if a >= 0:
            return a / b
        else:
            return "Negative Numerator"
    else:
        return "Division by Zero Error"

# Clean Pythonic Function with Early Return Guard Clauses:
def divide_clean(a, b):
    if b == 0:
        return "Division by Zero Error"  # Guard 1: Exit immediately
    if a < 0:
        return "Negative Numerator"       # Guard 2: Exit immediately
        
    return a / b  # Primary business logic at top level

print("Clean Function Output 1:", divide_clean(10, 2))
print("Clean Function Output 2:", divide_clean(10, 0))
OUTPUT
Clean Function Output 1: 5.0
Clean Function Output 2: Division by Zero Error

7. Docstrings and Type Hinting Essentials

Professional engineering requires documenting functions clearly. Python supports Docstrings (triple-quoted documentation strings) and Type Hints (specifying expected types for static analysis).

DOCSTRING_TYPE_HINTS.PY
def calculate_discount(price: float, discount_pct: float = 0.10) -> float:
    """
    Calculates discounted price from base price and percentage.

    Parameters:
        price (float): Base monetary price.
        discount_pct (float): Discount rate (default 0.10 for 10%).

    Returns:
        float: Discounted net price.
    """
    return price * (1.0 - discount_pct)

# Accessing function documentation programmatically
print("Function Docstring:")
print(calculate_discount.__doc__)

# Executing function
final_price = calculate_discount(100.0, 0.25)
print(f"Calculated Final Price: ${final_price:.2f}")
OUTPUT
Function Docstring:

    Calculates discounted price from base price and percentage.

    Parameters:
        price (float): Base monetary price.
        discount_pct (float): Discount rate (default 0.10 for 10%).

    Returns:
        float: Discounted net price.
    
Calculated Final Price: $75.00

8. Frequently Asked Interview Questions with Answers

Q1: What happens if a Python function finishes executing without an explicit `return` statement?
Answer: Python automatically returns the default singleton value None.
Q2: How does Python support returning multiple values from a single function call?
Answer: When multiple values separated by commas are returned (e.g., return x, y, z), Python implicitly packs those values into a single tuple object. The caller can then immediately unpack the tuple into individual variables.
Q3: What is the difference between Function Definition and Function Invocation?
Answer: Function definition (using def) binds the code block to an identifier name in memory without executing it. Function invocation occurs when the function name is called with parentheses (), passing arguments and triggering execution of the internal block.
Q4: What is a Guard Clause, and how does it improve code maintainability?
Answer: A Guard Clause is a conditional return statement placed at the top of a function to handle invalid inputs or boundary cases early. It eliminates deep nested if-else blocks, keeping the primary logic unindented at the top structural level.
Q5: What are Type Hints in Python functions, and do they enforce strict runtime type checks?
Answer: Type Hints (e.g., def add(a: int) -> int:) document expected parameter and return types for readability and static type checkers like mypy. However, Python does NOT enforce type hints strictly at runtime; passing a string where an integer is typed will not throw an automatic TypeError unless operations inside fail.

9. Homework & Practical Assignments

Task 1: String Sanitizer & Domain Extractor Function

Create a script named email_helpers.py inside your lesson_15 directory:

  • Define a function parse_email(raw_email: str) that takes a raw string email.
  • Use .strip() and .lower() to clean the string.
  • Include a guard clause returning (None, None) if "@" is not present in the string.
  • Use .split("@") to extract username and domain, returning them as two separate values.
  • Call the function with valid and invalid email inputs and print formatted results using f-strings.

Task 2: Financial Interest & Tax Calculator with Early Returns

Create a script named financial_calc.py:

  • Define a function calculate_loan_payback(principal: float, rate: float, years: int).
  • Add guard clauses: If principal <= 0 or rate < 0 or years <= 0, return string "ERROR: Invalid input values.".
  • Calculate total payback using simple interest formula: $Total = Principal + (Principal \times Rate \times Years)$.
  • Return the rounded total floating-point amount.

Task 3: Comprehensive Review Project — Order Management Pipeline (`order_processor_os.py`)

Project Goal: Build a complete modular command-line script named order_processor_os.py integrating **ALL concepts learned across Lessons 1 through 15**.

Project Architectural Requirements:

  1. Modular Functions (Lesson 15): Structure the entire code into dedicated functions:
    • calculate_tax(subtotal: float) -> float
    • apply_discount(subtotal: float, tier: str) -> float
    • process_command(command_list: list, order_state: dict) -> str
  2. Looping & State Management (Lessons 13-14): Wrap the application in a while True loop allowing continuous order entry. Process items using for loops with enumerate().
  3. Pattern Matching (Lesson 12): Inside process_command(), use match-case pattern matching to handle commands:
    • case ["ADD", item_name, price_str, qty_str] if price_str.replace('.', '', 1).isdigit() → Parse inputs, compute cost, and update order list.
    • case ["CHECKOUT", customer_tier] → Process complete order breakdown and exit loop using a sentinel flag.
    • case ["RESET"] → Clear current order list.
    • case _ → Return error string.
  4. Conditionals & Logic (Lessons 10-11): Use if-elif-else ladders inside apply_discount() to evaluate member discount rates (Gold = 20%, Silver = 10%, Regular = 0%).
  5. String Processing & Formatting (Lessons 8-9): Clean all inputs using .strip() and .upper(). Print an itemized invoice table using f-strings with alignment padding (:<15, :>10) and currency formatting (:,.2f).
  6. Math & Memory Foundations (Lessons 1-7): Perform float calculations rounded to 2 decimal places, maintain constants, write clear docstrings, and adhere to PEP 8 standards.

10. File & Workspace Directory Structure

Standard Course Workspace Layout:

Ensure all exercise files are stored inside their corresponding lesson directories:

python_mastery_course/
│
├── lesson_01/ ... lesson_14/
│
└── lesson_15/
    ├── basic_function_definition.py
    ├── function_with_parameters.py
    ├── return_value_demo.py
    ├── multiple_returns_demo.py
    ├── function_match_case_integration.py
    ├── guard_clause_pattern.py
    ├── docstring_type_hints.py
    ├── email_helpers.py             <-- (Task 1)
    ├── financial_calc.py            <-- (Task 2)
    └── order_processor_os.py        <-- (Task 3: Master Review Capstone)
        

11. What We Will Learn Next

Next Up: Lesson 16 — Parameters, Arguments and Scope

Now that you master defining functions and working with return values, we will explore advanced parameter mechanisms and memory variable scope.

In the next lesson, we will cover:

  • Positional vs Keyword Arguments in function calls.
  • Default Parameter values and the Dangerous Mutable Default Argument pitfall.
  • Arbitrary Variable-Length Arguments: *args (positional tuple) and **kwargs (keyword dictionary).
  • Variable Scope and Namespace Hierarchy: The LEGB Rule (Local, Enclosing, Global, Built-in).
  • Modifying global state safely using global and nonlocal keywords.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
Address Contact

+91 7877547686

E-mail

onlinecbtportal@gmail.com

Helpline Number

+91 7877547686


Click To Download
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat