Courses/Python/Functional Programming

    Advanced Lesson

    Functional Programming Techniques in Python

    Master functional programming patterns, pure functions, composition, and advanced FP architectures

    What Functional Programming Actually Means

    Functional programming is based on core principles:

    PrincipleWhat It MeansReal-World Analogy
    Pure FunctionsSame input → same output, no side effectsA calculator: 2+2 always equals 4
    ImmutabilityData never changes; create new copiesEditing a photo creates a new file
    First-Class FunctionsFunctions can be passed around like dataGiving someone a recipe card to follow
    Higher-Order FunctionsFunctions that work with other functionsA chef who teaches other chefs techniques
    Declarative StyleDescribe what, not how"Make me a sandwich" vs step-by-step instructions
    • Functions are first-class citizens — can be stored, passed, returned
    • No mutating state — create new data instead of modifying
    • Pure functions — no side effects, predictable output
    • Immutability — treat data as unchangeable
    • Declarative style — describe what you want, not how

    Pure Functions

    A pure function has no side effects, doesn't modify external state, and always produces the same output for the same input.

    Pure vs Impure Functions

    Understand the difference between pure and impure functions

    Try it Yourself »
    Python
    # Pure function - predictable, no side effects
    def pure_add(x, y):
        return x + y
    
    print(pure_add(2, 3))  # Always returns 5
    print(pure_add(2, 3))  # Still returns 5
    
    # Impure function - has side effects
    count = 0
    
    def impure_increment():
        global count
        count += 1
        return count
    
    print(impure_increment())  # 1
    print(impure_increment())  # 2 (different result!)
    
    # Pure functions are:
    # ✓ easier to test
    # ✓ easier to debug
    # ✓ safer to parallelize
    # ✓ more reliable

    Immutability in Python

    FP encourages transforming data instead of mutating it. Use immutable types and return new values.

    Immutability in Python

    Use immutable data structures for safer functional code

    Try it Yourself »
    Python
    # Immutable types: int, float, str, tuple, frozenset
    # Mutable types: list, dict, set
    
    # FP style - transform, don't mutate
    nums = [1, 2, 3, 4, 5]
    
    # Good FP style - create new list
    doubled = [x * 2 for x in nums]
    print(f"Original: {nums}")
    print(f"Doubled: {doubled}")
    
    # Avoid mutation (when following FP)
    # nums.append(6)  # modifies original
    
    # Using tuples for immutability
    point = (3, 4)
    # point[0] = 5  # Error! Tuples are immutable
    
    # Frozen sets
    fs = frozenset([1, 2, 3])
    # fs.add(4)  # Erro
    ...

    Higher-Order Functions

    Functions that take functions as arguments or return functions. Core to functional programming.

    Higher-Order Functions

    Functions that take or return other functions

    Try it Yourself »
    Python
    # Higher-order function - takes function as argument
    def apply_twice(func, value):
        return func(func(value))
    
    def add_one(x):
        return x + 1
    
    def double(x):
        return x * 2
    
    result1 = apply_twice(add_one, 5)
    print(f"Apply add_one twice to 5: {result1}")  # 7
    
    result2 = apply_twice(double, 3)
    print(f"Apply double twice to 3: {result2}")   # 12
    
    # Higher-order function - returns a function
    def make_multiplier(n):
        def multiplier(x):
            return x * n
        return multiplier
    
    times_3 = ma
    ...

    map(), filter(), reduce() — Core FP Tools

    The fundamental functional transformations for working with sequences.

    map, filter, reduce

    Core functional transformations for sequences

    Try it Yourself »
    Python
    from functools import reduce
    
    nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    # map() - transform each element
    doubled = list(map(lambda x: x * 2, nums))
    print(f"Doubled: {doubled}")
    
    # filter() - keep only matching items
    evens = list(filter(lambda x: x % 2 == 0, nums))
    print(f"Evens: {evens}")
    
    # reduce() - combine into single value
    total = reduce(lambda a, b: a + b, nums)
    print(f"Sum: {total}")
    
    product = reduce(lambda a, b: a * b, nums)
    print(f"Product: {product}")
    
    # Chaining operations
    result = lis
    ...

    Lambda Functions

    Anonymous functions perfect for functional pipelines and quick transformations.

    Lambda Functions

    Anonymous functions for functional pipelines

    Try it Yourself »
    Python
    # Basic lambda syntax
    square = lambda x: x * x
    print(f"Square of 5: {square(5)}")
    
    # Lambdas with multiple arguments
    add = lambda x, y: x + y
    print(f"3 + 4 = {add(3, 4)}")
    
    # Lambdas in sorting
    users = [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 25},
        {"name": "Charlie", "age": 35}
    ]
    
    sorted_by_age = sorted(users, key=lambda u: u["age"])
    print("\nSorted by age:")
    for user in sorted_by_age:
        print(f"  {user['name']}: {user['age']}")
    
    # Lambdas in functional chains
    nums = 
    ...

    Function Composition

    Building complex operations by chaining simple pure functions.

    Function Composition

    Build complex operations by chaining simple functions

    Try it Yourself »
    Python
    # Composition utility
    def compose(*funcs):
        def wrapper(x):
            for f in reversed(funcs):
                x = f(x)
            return x
        return wrapper
    
    # Simple functions
    double = lambda x: x * 2
    increment = lambda x: x + 1
    square = lambda x: x * x
    
    # Compose them
    f1 = compose(increment, double)
    print(f"Double then increment 5: {f1(5)}")  # 11
    
    f2 = compose(square, increment, double)
    print(f"Double, increment, square 3: {f2(3)}")  # 49
    
    # String processing pipeline
    clean = compose(
        str.st
    ...

    functools.partial — Pre-Configuring Functions

    Create specialized versions of functions by "freezing" some arguments.

    functools.partial

    Pre-configure functions by freezing arguments

    Try it Yourself »
    Python
    from functools import partial
    import operator
    
    # Basic partial application
    def power(base, exp):
        return base ** exp
    
    square = partial(power, exp=2)
    cube = partial(power, exp=3)
    
    print(f"5² = {square(5)}")
    print(f"5³ = {cube(5)}")
    
    # With operators
    times_10 = partial(operator.mul, 10)
    result = list(map(times_10, [1, 2, 3, 4, 5]))
    print(f"\nMultiply by 10: {result}")
    
    # Practical example: logging with context
    def log_message(level, message, context=""):
        print(f"[{level}] {message} {context
    ...

    Generator-Based Functional Programming

    Generators provide lazy evaluation and memory-efficient functional pipelines.

    Generator-Based FP

    Lazy evaluation with generator pipelines

    Try it Yourself »
    Python
    # Generator pipeline for processing data
    def numbers(n):
        """Generate numbers"""
        for i in range(n):
            yield i
    
    def only_evens(nums):
        """Filter to only evens"""
        for n in nums:
            if n % 2 == 0:
                yield n
    
    def squared(nums):
        """Square each number"""
        for n in nums:
            yield n ** 2
    
    # Chain generators (lazy evaluation)
    pipeline = squared(only_evens(numbers(10)))
    
    print("Processing numbers 0-9:")
    for result in pipeline:
        print(f"  {result}")
    
    # File
    ...

    Advanced: Currying

    Transform multi-argument functions into chains of single-argument functions.

    Currying

    Transform multi-arg functions into chains

    Try it Yourself »
    Python
    # Manual currying
    def curry_add(a):
        def add_b(b):
            def add_c(c):
                return a + b + c
            return add_c
        return add_b
    
    result = curry_add(1)(2)(3)
    print(f"Curried add: {result}")
    
    # Generic curry decorator
    def curry(func):
        """Transform f(a, b, c) into f(a)(b)(c)"""
        def curried(a):
            return lambda b: lambda c: func(a, b, c)
        return curried
    
    @curry
    def multiply(a, b, c):
        return a * b * c
    
    result = multiply(2)(3)(4)
    print(f"Curried multiply: {result}")
    
    ...

    Decorators — Functional Power Tools

    Decorators are higher-order functions that transform and enhance functions.

    Decorators as FP

    Higher-order functions that transform functions

    Try it Yourself »
    Python
    from functools import wraps
    import time
    
    # Simple logging decorator
    def log_calls(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(f"Calling {func.__name__}({args}, {kwargs})")
            result = func(*args, **kwargs)
            print(f"  → {result}")
            return result
        return wrapper
    
    @log_calls
    def add(a, b):
        return a + b
    
    print("Example 1: Logging")
    add(3, 5)
    add(10, 20)
    
    # Timing decorator
    def timer(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
          
    ...

    Functional Error Handling

    Handle errors with values instead of exceptions, enabling safer composition.

    Functional Error Handling

    Handle errors with values, not exceptions

    Try it Yourself »
    Python
    # Option/Maybe pattern
    class Maybe:
        def __init__(self, value):
            self.value = value
        
        def bind(self, func):
            if self.value is None:
                return Maybe(None)
            try:
                return Maybe(func(self.value))
            except:
                return Maybe(None)
        
        def get_or(self, default):
            return self.value if self.value is not None else default
    
    # Safe operations
    def safe_divide(x):
        return 100 / x if x != 0 else None
    
    def double(x):
        return x * 
    ...

    Immutable Data Structures

    Use frozen dataclasses and immutable collections for safer functional code.

    Immutable Data Structures

    Frozen dataclasses and immutable collections

    Try it Yourself »
    Python
    from dataclasses import dataclass
    from typing import FrozenSet
    
    # Frozen dataclass (immutable)
    @dataclass(frozen=True)
    class Point:
        x: int
        y: int
        
        def move(self, dx, dy):
            """Returns new Point instead of modifying"""
            return Point(self.x + dx, self.y + dy)
    
    p1 = Point(0, 0)
    p2 = p1.move(3, 4)
    print(f"Original: {p1}")
    print(f"Moved: {p2}")
    
    # p1.x = 10  # Error! Frozen dataclass is immutable
    
    # Frozen dataclass with methods
    @dataclass(frozen=True)
    class User:
        id:
    ...

    Real-World Functional Pipeline

    A complete functional architecture for data processing.

    Real-World Functional Pipeline

    Complete functional data processing architecture

    Try it Yourself »
    Python
    from functools import reduce
    
    # Pure transformation functions
    def parse_line(line):
        """Parse CSV-like line"""
        parts = line.strip().split(",")
        return {"name": parts[0], "value": int(parts[1])}
    
    def is_valid(record):
        """Check if record is valid"""
        return record["value"] > 0
    
    def extract_value(record):
        """Extract just the value"""
        return record["value"]
    
    def sum_values(acc, value):
        """Accumulator for reduce"""
        return acc + value
    
    # Sample data
    data = """Alice,100
    ...

    Summary

    You've learned comprehensive functional programming in Python:

    • Pure functions and immutability principles
    • Higher-order functions and function composition
    • map(), filter(), reduce() and lambda functions
    • functools utilities (partial, lru_cache, reduce)
    • Generator-based lazy evaluation
    • Advanced patterns: currying, decorators, monads
    • Functional error handling with Maybe/Result
    • Immutable data structures
    • Real-world functional pipelines

    Functional programming helps you build cleaner, more predictable, and easier-to-maintain code. These patterns are essential for data engineering, ML pipelines, ETL systems, and modern backend architectures.

    📋 Quick Reference — Functional Programming

    Tool / SyntaxWhat it does
    map(fn, iterable)Apply fn to every element
    filter(fn, iterable)Keep elements where fn returns True
    functools.reduce(fn, iterable)Accumulate into a single value
    lambda x: x * 2Anonymous inline function
    functools.partial(fn, arg)Pre-fill some function arguments

    🎉 Great work! You've completed this lesson.

    You can now write purely functional Python using map, filter, reduce, and composition — essential for data pipelines and ML workflows.

    Up next: Metaprogramming — write code that generates and inspects other code at runtime.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service