PythonDefining FunctionsBest Practices & Tooling

Function Best Practices & Tooling

Writing a function that works is only the first step. Writing a function that is reliable, readable, maintainable, and easy to debug is what separates professional code from a simple script. This guide covers the essential best practices and tools that will help you write high-quality Python functions.

Core Design Principles

Good functions are like good tools: they are simple, do one job well, and are easy to understand.

Single Responsibility Principle (SRP)

A function should do one thing, and do it well. If your function description includes the word “and” (e.g., “it validates the data and writes it to a file”), it’s a sign that it might be doing too much.

Bad: A function that does everything.

def process_user_data(data):
    # 1. Validates data
    if not data.get("name") or not data.get("email"):
        print("Error: Missing data")
        return
    # 2. Saves to database
    print(f"Saving {data['name']} to database...")
    # 3. Sends an email
    print(f"Sending welcome email to {data['email']}...")

Good: Split into separate, focused functions.

def validate_user(data):
    if not data.get("name") or not data.get("email"):
        raise ValueError("User data is incomplete.")
 
def save_user_to_db(user):
    print(f"Saving {user['name']} to database...")
 
def send_welcome_email(email):
    print(f"Sending welcome email to {email}...")
 
# Now you can compose them
user_data = {"name": "Alice", "email": "alice@example.com"}
try:
    validate_user(user_data)
    save_user_to_db(user_data)
    send_welcome_email(user_data["email"])
except ValueError as e:
    print(e)

Robust Error Handling

Don’t let your functions fail silently. Use Python’s exception system to signal errors clearly.

Pyground

Create a `divide` function that raises specific errors for invalid input.

Expected Output:


5.0
An error occurred: Both numerator and denominator must be numbers.

Output:

Documentation with Docstrings

Every function you intend to reuse should have a docstring explaining its purpose, arguments, and return value.

Pyground

Write a function with a Google-style docstring.

Expected Output:

Docstring: Calculates compound interest.

  Args:
      principal (float): The initial principal amount.
      rate (float): The annual interest rate (as a decimal, e.g., 0.05 for 5%).
      time (int): The number of years the money is invested for.
      n (int, optional): The number of times that interest is compounded per year. 
                         Defaults to 1.

  Returns:
      float: The total amount after compound interest.
  

Output:

Essential Tooling

Leverage automated tools to maintain code quality.

  • Linters (Ruff, Flake8, Pylint): These tools analyze your code for style violations (e.g., line length, variable naming), programming errors (e.g., unused variables), and code complexity. They are like a grammar checker for your code.
  • Type Checkers (Mypy): If you use type hints (name: str), mypy can statically analyze your code to find type-related bugs before you even run it, like passing a list where a dict is expected.
  • Testing Frameworks (pytest): pytest is the standard for testing in Python. It makes writing small, readable tests easy.

Most modern code editors can integrate these tools to give you real-time feedback as you type.