Python
  • Intro.
  • Catalogue
  • Chapter 1: Introduction to Python
  • Chapter 2: Python Syntax and Fundamentals
    • Chapter: Variables and Data Types in Python
  • Chapter 3: Control Flow
  • Chapter 4: Functions
  • Chapter 5: Data Structures
  • Chapter 6: Object-Oriented Programming (OOP)
  • Chapter 7: Modules and Packages
  • Chapter 8: File Handling
  • Chapter 9: Error and Exception Handling
  • Chapter 10: Working with Databases
  • Chapter 11: Iterators and Generators
  • Chapter 12: Decorators and Context Managers
  • Chapter 13: Concurrency and Parallelism
  • Chapter 14: Testing and Debugging
  • Chapter 15: Web Development with Python
  • Chapter 16: Data Science and Machine Learning with Python
  • Chapter 17: Working with APIs
  • Chapter 18: Automation with Python
  • Chapter 19: Python and Cloud/DevOps
  • Chapter 20: Python and IoT
  • Appendices
Powered by GitBook
On this page

Chapter 4: Functions

Functions are reusable blocks of code designed to perform a specific task. They help organize code, reduce repetition, and improve readability and maintainability. In Python, functions are first-class objects, meaning they can be passed around as arguments, returned from other functions, and assigned to variables.

Defining and Calling Functions

A function must be defined before it can be called. Use the def keyword to define a function. Functions can take inputs, perform tasks, and optionally return outputs.

Syntax:

def function_name(parameters):
    """Optional documentation string (docstring)"""
    # Code block
    return value  # Optional

Example:

def greet(name):
    """This function returns a greeting message."""
    return f"Hello, {name}!"

# Calling the function
greeting = greet("Alice")
print(greeting)

Key Points:

  • Function names should follow the same naming rules as variables.

  • Parameters are optional; a function can take zero or more arguments.

  • The return statement is optional but allows the function to send a result back to the caller.

  • Include a docstring to describe the function’s purpose and behavior.

Parameters and Arguments

Types of Parameters:

  1. Positional Parameters: Must be provided in the order they appear in the function definition.

    def multiply(a, b):
        return a * b
    
    print(multiply(2, 3))  # Output: 6
  2. Default Parameters: Provide default values for arguments, making them optional.

    def greet(name="Guest"):
        print(f"Hello, {name}!")
    
    greet()  # Output: Hello, Guest!
    greet("Alice")  # Output: Hello, Alice!
  3. Keyword Arguments: Allow specifying arguments by name, regardless of their order.

    def divide(numerator, denominator):
        return numerator / denominator
    
    print(divide(denominator=4, numerator=8))  # Output: 2.0
  4. Arbitrary Arguments: Use *args for non-keyword variable-length arguments and **kwargs for keyword variable-length arguments.

    def print_all(*args, **kwargs):
        print("Positional:", args)
        print("Keyword:", kwargs)
    
    print_all(1, 2, 3, a="apple", b="banana")
    # Positional: (1, 2, 3)
    # Keyword: {'a': 'apple', 'b': 'banana'}

Return Values

A function can return a value to the caller using the return statement. If no return is provided, the function implicitly returns None.

Examples:

def square(num):
    return num ** 2

print(square(4))  # Output: 16

# Multiple return values

def stats(numbers):
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

print(stats([1, 2, 3, 4, 5]))  # Output: (1, 5, 3.0)

Scope and Lifetime of Variables

Scope determines where a variable can be accessed, while lifetime refers to how long it exists.

Types of Scope:

  1. Local Scope: Variables declared inside a function are accessible only within that function.

    def test():
        x = 10  # Local variable
        print(x)
    
    test()
    # print(x)  # Error: x is not defined
  2. Global Scope: Variables declared outside all functions are accessible everywhere.

    x = 10  # Global variable
    def test():
        print(x)
    
    test()
    print(x)
  3. Global Keyword: Used to modify a global variable inside a function.

    x = 10
    def modify():
        global x
        x = 20
    
    modify()
    print(x)  # Output: 20

Lifetime:

  • Local variables are destroyed when the function execution ends.

  • Global variables persist throughout the program’s execution.

Lambda Functions

Lambda functions are anonymous, single-line functions defined using the lambda keyword. They are useful for short, simple operations.

Syntax:

lambda arguments: expression

Examples:

# Single-argument lambda
square = lambda x: x ** 2
print(square(5))  # Output: 25

# Multi-argument lambda
add = lambda a, b: a + b
print(add(3, 7))  # Output: 10

# Sorting with lambda
names = ["Alice", "Bob", "Charlie"]
names.sort(key=lambda name: len(name))
print(names)  # Output: ['Bob', 'Alice', 'Charlie']

Key Points:

  • Lambda functions can have multiple arguments but only one expression.

  • They are often used with higher-order functions like map(), filter(), and reduce().

Higher-Order Functions

Functions that accept other functions as arguments or return them as results are called higher-order functions.

Examples:

# Using map()
numbers = [1, 2, 3, 4]
squares = map(lambda x: x ** 2, numbers)
print(list(squares))  # Output: [1, 4, 9, 16]

# Using filter()
numbers = [1, 2, 3, 4]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens))  # Output: [2, 4]

# Using reduce()
from functools import reduce
numbers = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, numbers)
print(product)  # Output: 24

Best Practices

  1. Use meaningful names for functions and parameters.

  2. Keep functions short and focused on a single task.

  3. Document functions with docstrings.

  4. Avoid using global variables; prefer passing arguments to functions.

  5. Test functions independently.

Exercises

Exercise 1:

Write a function that calculates the greatest common divisor (GCD) of two numbers.

Solution:

def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

print(gcd(48, 18))  # Output: 6

Exercise 2:

Write a function to generate the Fibonacci sequence up to a given number n.

Solution:

def fibonacci(n):
    sequence = []
    a, b = 0, 1
    while a < n:
        sequence.append(a)
        a, b = b, a + b
    return sequence

print(fibonacci(10))  # Output: [0, 1, 1, 2, 3, 5, 8]

Exercise 3:

Write a function that accepts another function as an argument and applies it to a list of numbers.

Solution:

def apply_function(func, numbers):
    return [func(num) for num in numbers]

print(apply_function(lambda x: x ** 2, [1, 2, 3, 4]))  # Output: [1, 4, 9, 16]

In the next chapter, we will explore Python’s data structures, including lists, tuples, dictionaries, and sets.

PreviousChapter 3: Control FlowNextChapter 5: Data Structures

Last updated 5 months ago