Fundamentals 8 min read

7 Common Pitfalls in Python Function Writing and How to Avoid Them

This article explains the most frequent mistakes developers make when defining Python functions—such as mutable default arguments, inconsistent return types, overly large functions, outdated string formatting, missing type hints, manual index tracking, and misuse of try‑except for flow control—and provides clear, best‑practice solutions with code examples to write cleaner, more maintainable, and efficient Python code.

IT Services Circle
IT Services Circle
IT Services Circle
7 Common Pitfalls in Python Function Writing and How to Avoid Them

Python is like a magical Swiss‑army knife—its concise syntax and expressive power let beginners start quickly, yet even seasoned developers often fall into hidden traps when defining functions.

1. Stop Using Mutable Default Arguments!

Wrong way:

Python initializes default parameters only once at function definition, not at each call, so a list defined as a default value is shared across calls, leading to unexpected behavior.

def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item('apple'))  # ['apple']
print(add_item('banana'))  # ['apple', 'banana'] ???

Correct way:

Always use None as the default and create a new list inside the function.

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item('apple'))  # ['apple']
print(add_item('banana'))  # ['banana']

2. Do Not Return Different Data Types

Wrong way:

Returning inconsistent types makes the function harder to use and can cause runtime errors.

def process(value):
    if value > 10:
        return "Success"
    else:
        return 0  # Mixing str and int

Correct way:

Return a single, predictable type (or None ) and use type hints for clarity.

from typing import Optional

def process(value: int) -> Optional[str]:
    return "Success" if value > 10 else None

3. Keep Functions Small and Focused

Wrong way:

A function that calculates price, tax, discount, and shipping all at once becomes hard to test and maintain.

def calculate_price(quantity, price, tax_rate, discount, shipping):
    total = (quantity * price) + shipping
    total += total * tax_rate
    if discount:
        total -= total * discount
    return total

Correct way (decompose):

Split the logic into tiny, single‑purpose functions and compose them.

def calculate_subtotal(quantity, price):
    return quantity * price

def apply_tax(subtotal, tax_rate):
    return subtotal + (subtotal * tax_rate)

def apply_discount(amount, discount):
    return amount - (amount * discount)

def calculate_total(quantity, price, tax_rate, discount, shipping):
    subtotal = calculate_subtotal(quantity, price)
    taxed_total = apply_tax(subtotal, tax_rate)
    discounted_total = apply_discount(taxed_total, discount)
    return discounted_total + shipping

4. Use f‑Strings Instead of Old‑Style Formatting

Wrong way:

def greet(name, age):
    return "Hello, my name is %s and I am %d years old." % (name, age)

Correct way (more readable and efficient):

def greet(name, age):
    return f"Hello, my name is {name} and I am {age} years old."

f‑strings are faster and clearer, making them the preferred way to format strings in Python.

5. Leverage Type Hints for Clarity

Wrong way:

Without hints it is unclear whether a and b are ints, floats, or strings.

def add_numbers(a, b):
    return a + b

Correct way:

Adding explicit type hints makes the function self‑documenting and prevents accidental misuse.

def add_numbers(a: int, b: int) -> int:
    return a + b

6. Use enumerate() Instead of Manual Index Tracking

Wrong way:

fruits = ["apple", "banana", "cherry"]
index = 0
for fruit in fruits:
    print(f"{index}: {fruit}")
    index += 1

Correct way:

enumerate() removes the need for a manual counter, making loops cleaner and more Pythonic.

fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

7. Avoid Using try‑except for Flow Control

Wrong way:

def get_price(data):
    try:
        return data["price"]
    except KeyError:
        return 0

Correct way:

Use .get() which is more readable and avoids unnecessary exception handling.

def get_price(data):
    return data.get("price", 0)

Writing better Python functions is not just about making them work; it is about making them readable, maintainable, and efficient. By avoiding these common mistakes and following the best practices above, you will produce cleaner, more professional Python code.

Now that you know how to improve Python functions, go back to your old code and refactor it—you’ll be surprised at how much cleaner and faster it becomes.

Have more function‑writing tips? Feel free to leave a comment below!

Pythonbest practicesError HandlingFunctionsenumeratetype hintsf-strings
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.