๐Ÿงน Easy Losses

Using Lists in the Wrong Place

Anti-pattern: Using lists for operations that require frequent lookups, insertions, and deletions:

# Inefficient for frequent lookups
my_list = [1, 2, 3, 4, 5]
if 4 in my_list:
    print("Found!")

Solution: Using sets or dicts for frequent lookups and insertions:

my_set = {1, 2, 3, 4, 5}
if 4 in my_set:  # Much faster lookup
    print("Found!")

Avoiding List Comprehensions / Generator Expressions

Anti-pattern: Using loops to generate lists or to iterate over collections increases complexity:

result = []
for i in range(100):
    if i % 2 == 0:
        result.append(i*i)

Solution: Use list comprehensions for more concise and faster code:

result = [i*i for i in range(100) if i % 2 == 0]

When the result list is not needed all at once, use generator expressions to save memory:

result = (i*i for i in range(100) if i % 2 == 0)

Misusing the Global Interpreter Lock (GIL)

Anti-pattern: Relying solely on threads for concurrency in CPU-bound tasks can be inefficient, due to the GIL:

from threading import Thread

# This might not speed up due to GIL in CPU-bound tasks
def compute_heavy():
    # Some heavy computation
    pass

threads = [Thread(target=compute_heavy) for _ in range(4)]
for thread in threads:
    thread.start()
for thread in threads:
    thread.join()

Solution: Use multiprocessing or libraries like concurrent.futures.ProcessPoolExecutor for CPU-bound tasks:

from multiprocessing import Pool

def compute_heavy():
    # Some heavy computation
    pass

with Pool(4) as p:
    p.map(compute_heavy, [1, 2, 3, 4])

Under-Utilising Built-in Functions / Libraries

Anti-pattern: Reimplementing functionality that is already provided (and optimised) by Python's built-in functions or standard libraries.

# Custom implementation of a feature that exists in standard library
def manual_sort(my_list):
    return sorted(my_list)  # Inefficient and reinventing the wheel

# Correct approach
my_list = [3, 1, 4, 1, 5]
print(sorted(my_list))

Solution: Always check the Python standard library and built-in functions before implementing common algorithms and data structures.

Deeply Nested Functions

Anti-pattern: Writing deeply nested functions or loops, which can make code hard to read, debug, and optimise.

def deeply_nested(data):
    for i in data:
        for j in i:
            # ... more nested loops or conditions
            pass

Solution: Refactor deeply nested loops into separate functions or use more efficient data structures or algorithms to simplify the logic.

By being aware of these common anti-patterns and applying the suggested solutions, you can quickly improve the performance and maintainability of your Python code.

Get PDF