Python Performance Optimization: 10 Core Techniques Every Beginner Should Master (Including Code Demonstrations)

Python’s slow performance is not due to being an “interpreted” language, but rather due to incorrect data structure choices, excessive unnecessary object creation, repeated function calls, and misuse of exceptions. There are only two categories of underlying principles:

  1. 1. Reduce time complexity
  2. 2. Reduce memory usage and object overhead

The following sections will elaborate on these two categories and demonstrate with minimal code “why it is indeed faster”.

1. Optimizations Based on Time Complexity

1. Use set instead of list for membership testing

Principle

<span>list</span> lookup is O(n), while <span>set</span> is a hash structure with an average of O(1).

Incorrect Implementation (Slow)

nums = list(range(100000))
print(50000 in nums)     # O(n)

Correct Implementation (Much Faster)

nums_set = set(range(100000))
print(50000 in nums_set)  # O(1)

Why Beginners Should Master This Immediately

This is necessary for all scenarios involving “deduplication”, “filtering”, and “checking existence”.

2. bisect: Use binary search instead of linear search in sorted lists

Principle

Linear search O(n) → Binary search O(log n).

Incorrect Implementation

data = list(range(100000))
data.index(99999)   # O(n)

Correct Implementation

import bisect
data = list(range(100000))
pos = bisect.bisect_left(data, 99999)  # O(log n)

Application Scenarios

Leaderboards, timelines, continuously inserting into sorted sequences.

3. Avoid calling immutable functions in loops

Principle

Python function calls are expensive. Repeatedly calling a function that returns a fixed value in a loop is pointless.

Incorrect Implementation

import math
for i in range(1000000):
    x = math.pi  # Repeated call

Correct Implementation

import math
pi = math.pi
for i in range(1000000):
    x = pi

4. Encapsulate frequently used logic in local functions to reduce variable lookup costs

Principle

Python’s variable lookup order is: local > enclosed > global. Placing it inside a function is faster than placing it globally.

Incorrect Implementation

def add(x):  # Global scope lookup is slower
    return x + 1

for _ in range(1000000):
    add(1)

Correct Implementation

def run():
    def add_local(x):  # Local lookup is faster
        return x + 1

    for _ in range(1000000):
        add_local(1)

run()

5. Avoid using try/except for flow control (especially fatal in loops)

Principle

The overhead of exception handling is much higher than that of if statements.

Incorrect Implementation

lst = [1, 2, 3]
for i in range(100000):
    try:
        x = lst[5]  # Always raises an exception
    except IndexError:
        pass

Correct Implementation

lst = [1, 2, 3]
for i in range(100000):
    if len(lst) > 5:
        x = lst[5]

6. Use C extension modules like math / itertools

Principle

C implementations are several times faster than Python code.

Example: math vs custom implementation

import math

math.sqrt(9)  # Fast
9 ** 0.5      # Slow

Example: itertools instead of manual loops

import itertools

# All combinations
for a, b in itertools.combinations(range(5), 2):
    pass

This is faster than manually writing two nested loops, does not create intermediate lists, and uses less memory.

2. Optimizations Based on Memory and Object Management

7. Avoid unnecessary list/dictionary copying

Incorrect Implementation

data = [i for i in range(100000)]
copy = data[:]         # Unnecessary copy

Correct Implementation

data = [i for i in range(100000)]
# Directly use data

Principle

Copying = creating N new objects + new list memory allocation.

8. Preallocate lists when the size is known

Incorrect Implementation

arr = []
for i in range(100000):
    arr.append(i)  # Multiple expansions

Correct Implementation

arr = [0] * 100000  # Allocate all at once
for i in range(100000):
    arr[i] = i

Applicable Scenarios

Large loops, data pipelines, machine learning preprocessing.

9. Use slots to optimize object memory

Principle

By default, class instances have a <span>__dict__</span>, which consumes a lot of memory.<span>__slots__</span> directly tells the interpreter “I only have these attributes”.

Example

class Point:
    __slots__ = ('x', 'y')  # Limit attributes
    def __init__(self, x, y):
        self.x = x
        self.y = y

Significant savings when dealing with a large number of objects (over 100,000).

10. itertools’ lazy evaluation can avoid large memory structures

Incorrect Implementation (generating the entire list)

pairs = [(i, j) for i in range(1000) for j in range(1000)]

Correct Implementation (lazy, does not occupy memory)

import itertools
pairs = itertools.product(range(1000), range(1000))

This will not create a list of millions of elements at once.

Final Summary: Two Key Understandings Every Beginner Must Establish

1. Python is slow, not because of the language itself, but due to incorrect data structure choices and inefficient coding practices.

The complexity differences between lists, dictionaries, and sets account for 90% of performance bottlenecks.

2. Any occurrence of:

  • • Large loops
  • • Large data
  • • Repeated calculations
  • • A large number of objects
  • • Using exceptions as flow controlare all sources of performance degradation.

Mastering the above 10 points will immediately elevate your Python speed to a new level.

Leave a Comment