Dev.to AI ๐Ÿค– Ai ๐Ÿ‘ 0 ๐Ÿ“– 5 min read

๐Ÿ› ๏ธ Day 3 โ€“ Python Functions & Functional Power

Welcome to Day 3! Today, we transition from writing basic scripts to building reusable, modular, and highly flexible building blocks. We will look at how Python handles arguments, the strict rules of variable scope, and

Welcome to Day 3! Today, we transition from writing basic scripts to building reusable, modular, and highly flexible building blocks. We will look at how Python handles arguments, the strict rules of variable scope, and how functions can be treated as first-class citizens to create highly dynamic utilities. ๐Ÿš€

1. Parameters & Arguments (Default & Keyword-Only) โš™๏ธ

In Python, you can define parameters that make your functions incredibly flexible.

  • Default Arguments: Allow you to set fallback values for parameters if the caller doesn't provide them.
  • Keyword-Only Arguments: Enforce that certain arguments must be passed by name rather than position. You declare these by placing an asterisk * in your parameter list; everything after the * must be named.

๐ŸŒฑ Easy Starter Example

# 'msg' has a default value. 'shout' is a keyword-only argument.
def greet(name, msg="Hello", *, shout=False):
    greeting = f"{msg}, {name}!"
    return greeting.upper() if shout else greeting

# Usage
print(greet("Alice"))                 # Output: Hello, Alice!
print(greet("Bob", "Welcome"))        # Output: Welcome, Bob!
# print(greet("Charlie", shout=True)) # Output: HELLO, CHARLIE!
# greet("Dave", "Hi", True)           # โŒ TypeError: keyword-only argument required

Real-World Application Example: API Request Configurer ๐Ÿ”Œ

# Enforcing safety defaults for API timeouts and token visibility
def send_request(url, payload, *, timeout=10, retries=3):
    print(f"Sending data to {url} (Timeout: {timeout}s, Retries: {retries})")
    # Request logic would go here...

# Caller must explicitly state overrides, preventing accidental index errors
send_request("https://api.example.com", {"data": 1}, timeout=5, retries=1)

2. *args and kwargs (Dynamic Arity) ๐Ÿ“ฆ

Sometimes you don't know exactly how many arguments a user will pass to your function.

  • *args collects extra positional arguments into a Tuple.
  • kwargs collects extra keyword arguments into a Dictionary.

๐ŸŒฑ Easy Starter Example

def dynamic_demo(*args, **kwargs):
    print("args:", args)      # Tuple of positional args
    print("kwargs:", kwargs)  # Dict of keyword args

dynamic_demo(1, 2, 3, user="Dev", role="Admin")
# Output:
# args: (1, 2, 3)
# kwargs: {'user': 'Dev', 'role': 'Admin'}

Real-World Application Example: HTML Element Generator ๐ŸŽจ

def build_html_tag(tag_name, *content, **attributes):
    # Format the attributes dict into a string of key="value"
    attr_str = "".join([f' {key}="{val}"' for key, val in attributes.items()])
    # Join all separate content items together
    inner_text = " ".join(content)

    return f"<{tag_name}{attr_str}>{inner_text}</{tag_name}>"

# Create a customized HTML link
link = build_html_tag("a", "Click", "Here", "To", "Learn", href="https://python.org", target="_blank")
print(link)
# Output: <a href="https://python.org" target="_blank">Click Here To Learn</a>

3. Scope & The LEGB Rule ๐ŸŒ

Variable visibility in Python is governed by the LEGB Rule. When you look up a variable name, Python checks four scopes in a strict order:

  1. Local: Inside the current function.
  2. Enclosing: Inside any enclosing (outer) functions (relevant to nested functions/closures).
  3. Global: At the top level of the module/file.
  4. Built-in: Python's pre-loaded keywords (like len, sum, print).

๐ŸŒฑ Easy Starter Example

x = "Global"

def outer_function():
    x = "Enclosing"

    def inner_function():
        x = "Local"
        print(f"Inside inner: {x}") # Finds Local first

    inner_function()
    print(f"Inside outer: {x}")     # Finds Enclosing first

outer_function()
print(f"Global scope: {x}")         # Finds Global first

Real-World Application Example: Modifying Enclosing Scope ๐Ÿ”ง

# To modify variables in Global or Enclosing scopes, use 'global' or 'nonlocal'
def create_click_counter():
    count = 0  # Enclosing scope variable

    def click():
        nonlocal count  # Declares we want to edit 'count' from the outer function
        count += 1
        return count

    return click

counter = create_click_counter()
print(counter())  # Output: 1
print(counter())  # Output: 2

4. First-Class Functions & Closures ๐Ÿค

In Python, functions are First-Class Citizens. This means you can assign them to variables, pass them as arguments to other functions, and even return them from other functions.

A Closure is an inner function that "remembers" and has access to variables from its enclosing outer scope, even after the outer function has finished executing.

๐ŸŒฑ Easy Starter Example

def make_multiplier(factor):
    # This is a closure! It remembers 'factor'
    def multiply(number):
        return number * factor
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(10)) # Output: 20
print(triple(10)) # Output: 30

Real-World Application Example: Custom Logger Creator ๐Ÿ“

import datetime

# Create customized loggers with specific prefix headers
def make_logger(prefix: str):
    def log(message: str) -> None:
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        print(f"[{timestamp}] [{prefix.upper()}]: {message}")
    return log

# Instantiate tailored logging functions
info_log = make_logger("info")
error_log = make_logger("error")

# Usage
info_log("Server started successfully.")
error_log("Database connection timeout.")

5. Practice Challenge: Building Reusable Utility Functions ๐Ÿ‹๏ธ

Let's tie all these rules together to build a robust Data Processing Utility Engine.

We want to build a reusable utility function that processes data tables (lists of dictionaries) by applying custom transformations, filtering rules, and applying fallback configuration defaults.

# 1. Custom transformation functions (First-Class Functions)
def tax_calculator(amount):
    return amount * 1.15

def uppercase_formatter(text):
    return str(text).upper()


# 2. Main data processor utility utilizing *args, **kwargs, and keyword defaults
def process_transactions(transactions: list[dict], *fields_to_transform, transformer_func, **default_fallbacks) -> list[dict]:
    """
    Processes transaction logs by applying a 'transformer_func' to specified fields.
    Fills in any missing fields using key-value 'default_fallbacks'.
    """
    processed_data = []

    for item in transactions:
        # Create a shallow copy to keep the original list pure
        temp_item = item.copy()

        # Apply fallbacks for missing data
        for key, val in default_fallbacks.items():
            if key not in temp_item:
                temp_item[key] = val

        # Apply transformation to specified fields (passed via *args)
        for field in fields_to_transform:
            if field in temp_item:
                temp_item[field] = transformer_func(temp_item[field])

        processed_data.append(temp_item)

    return processed_data


# --- RUNNING THE UTILITY ---

raw_invoices = [
    {"invoice_id": "inv_001", "subtotal": 100},
    {"invoice_id": "inv_002", "subtotal": 250, "currency": "USD"},
    {"invoice_id": "inv_003"}, # Missing invoice_id and subtotal fields
]

# Run processor to apply tax calculation on subtotal and default missing currency to 'EUR'
completed_invoices = process_transactions(
    raw_invoices, 
    "subtotal",                 # *args: Fields to modify
    transformer_func=tax_calculator,  # Keyword-only transformer
    currency="EUR",             # **kwargs: Fallbacks
    subtotal=0.0                # **kwargs: Fallbacks
)

for invoice in completed_invoices:
    print(invoice)

# Output:
# {'invoice_id': 'inv_001', 'subtotal': 114.99999999999999, 'currency': 'EUR'}
# {'invoice_id': 'inv_002', 'subtotal': 287.5, 'currency': 'USD'}
# {'invoice_id': 'inv_003', 'currency': 'EUR', 'subtotal': 0.0}

๐Ÿ“ฐ Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.