Python Functions, Recursion, and Built-in Methods

Mathematical Functions vs Programming Functions

In mathematics, a function represents a deterministic mapping where each input x yields exactly one output y. It is stateless and purely evaluated. In programming, a function is a structured block of reusable logic designed to perform a specific task. While it can accept inputs and return outputs like a mathematical function, it may also interact with external state, resulting in different outputs for the same inputs depending on the program's broader context.

def calculate_increment(value):
    # Increments the provided value by one
    value += 1
    return value

The Purpose of Functions

Consider a monitoring script that checks system metrics and triggers alerts. Without functions, the logic for connecting to an email server, sending a message, and closing the connection would be duplicated for every metric checked (CPU, memory, disk). This violates the DRY (Don't Repeat Yourself) principle and makes maintenance difficult.

By extracting the alert logic into a function, the code becomes reusable, consistent, and easier to extend:

def dispatch_alert(message):
    # Connect to SMTP server
    # Send email with message
    # Close connection
    pass

while True:
    if cpu_usage > 90:
        dispatch_alert('CPU threshold exceeded')
    if disk_usage > 90:
        dispatch_alert('Disk space critically low')
    if memory_usage > 80:
        dispatch_alert('Memory usage high')

Benefits include code reusability, consistency across the application, and improved extensibility.

Functions vs Procedures

Historically, a procedure is a subroutine that does not return a value, whereas a function does. In Python, this distinction does not exist. If a function exits without explicitly calling return, the interpreter implicitly returns None.

def no_return():
    print('Executed without return')

def explicit_return():
    return 42

result1 = no_return()  # result1 is None
result2 = explicit_return()  # result2 is 42

Return value rules in Python:

  • No return or empty return: returns None
  • Returns one object: returns that object type
  • Returns multiple objects: returns them encapsulated in a tuple

Function Parameters

Formal parameters are the variables defined in the function signature. They only occupy memory during the function's execution. Actual parameters (arguments) are the concrete values passed to the function during the call.

  • Positional Arguments: Passed in order, matching the signature.
  • Keyword Arguments: Passed by explicitly naming the parameter, allowing out-of-order passing.
  • Default Parameters: Assigned a default value in the signature if no argument is provided.
  • Variable-length Arguments: *args captures excess positional arguments as a tuple; **kwargs captures excess keyword arguments as a dictionary.

Variable Scope: Local vs Global

Variables defined inside a function are local to that function and are destroyed upon exit. Variables defined at the module level are global and accessible throughout the file. If a local variable shares a name with a global one, the local variable takes precedence within the function. To modify a global variable inside a function, use the global keyword.

identifier = 'global_user'

def override_locally():
    identifier = 'local_user'
    print('Inside override_locally:', identifier)

def modify_global():
    global identifier
    identifier = 'modified_global_user'
    print('Inside modify_global:', identifier)

override_locally()  # Prints local_user
modify_global()     # Prints modified_global_user
print('Global scope:', identifier)  # Prints modified_global_user

Forward References and Nested Functions

Functions must be defined before they are called. Calling a function prior to its definition results in a NameError. Python also allows defining functions inside other functions. The scope of nested functions is bound to their definition location, not where they are called. This enables closures, where an inner function captures variables from its enclosing scope.

def outer_scope():
    status = 'active'

    def inner_scope():
        print('Captured status is:', status)

    return inner_scope

closure_func = outer_scope()
closure_func()  # Outputs: Captured status is active

Recursion

Recursion occurs when a function calls itself directly or indirectly. A valid recursive function requires two key components: a base case to terminate the recursion, and a progression toward that base case where the problem size diminishes with each call. Recursion can be inefficient and risks stack overflow if the recursion depth is too great, as each call adds a new frame to the call stack.

Binary search is a classic implementation of recursion:

def search_binary(arr, target):
    if len(arr) > 1:
        mid_idx = len(arr) // 2
        mid_val = arr[mid_idx]
        if mid_val == target:
            print('Found target:', mid_val)
        elif mid_val > target:
            return search_binary(arr[:mid_idx], target)
        else:
            return search_binary(arr[mid_idx+1:], target)
    else:
        if arr[0] == target:
            print('Found target:', arr[0])
        else:
            print('Target not found')

data = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
search_binary(data, 23)

Anonymous Functions (Lambda)

Anonymous functions, defined using the lambda keyword, are single-expression functions without a name. They are typically used where a simple function is required temporarily, often as an argument to higher-order functions.

# Standard function
def square(x):
    return x ** 2

# Equivalent lambda
square_lambda = lambda x: x ** 2

Functional Programming Tools

Functional programming treats computation as the evaluation of mathematical functions, avoiding state and mutable data. Python supports this paradigm through higher-order functions—functions that accept other functions as arguments or return them as results.

map()

Applies a given function to every item in an iterable and returns a map object (an iterator).

values = [1, 2, 3, 4]
squared = map(lambda x: x**2, values)
print(list(squared))  # [1, 4, 9, 16]

filter()

Constructs an iterator from elements of an iterable for which a function returns true.

names = ['alice', 'bob', 'anna', 'bill']
filtered = filter(lambda n: n.startswith('a'), names)
print(list(filtered))  # ['alice', 'anna']

reduce()

Applies a function of two arguments cumulatively to the items of an iterable, from left to right, reducing the iterable to a single value. It must be imported from functools.

from functools import reduce
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda acc, curr: acc + curr, numbers, 0)
print(total)  # 15

Essential Built-in Functions

Built-in functions like max(), min(), and sorted() can accept a key argument, which is often a lambda function, to determine the comparison logic.

payroll = {
    'alice': 5000,
    'bob': 8500,
    'charlie': 6200
}

# Find highest earner
top_earner = max(payroll, key=lambda k: payroll[k])
print(top_earner)  # bob

# Zip values and keys to compare by value, returning both
zipped = zip(payroll.values(), payroll.keys())
print(max(zipped))  # (8500, 'bob')

Tags: python functions Recursion lambda built-in functions

Posted on Thu, 15 Oct 2026 16:42:42 +0000 by step