Fundamentals 15 min read

Python Code Optimization Techniques for Faster Execution

This article presents practical Python performance‑boosting techniques, covering fundamental optimization principles, avoiding global variables and unnecessary attribute access, reducing data copying, improving loop structures, leveraging short‑circuit logic, using numba JIT compilation, and selecting appropriate built‑in data structures to achieve significant speed gains.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Python Code Optimization Techniques for Faster Execution

Introduction

This article shares pure‑Python programming acceleration methods, explaining why Python, as an interpreted language, can be slower than compiled languages and providing concrete tips to improve execution speed.

0. Code Optimization Principles

Principle 1: Do not optimize prematurely; ensure code works correctly before measuring performance.

Principle 2: Weigh the cost of optimization; consider time‑space trade‑offs and development effort.

Principle 3: Focus on hot spots, typically inner loops, rather than optimizing every part of the code.

1. Avoid Global Variables

Placing code inside functions reduces lookup time for variables, yielding a 15‑30% speed improvement.

# Not recommended – global variables (26.8 s)
import math
size = 10000
for x in range(size):
    for y in range(size):
        z = math.sqrt(x) + math.sqrt(y)

# Recommended – inside a function (20.6 s)
def main():
    size = 10000
    for x in range(size):
        for y in range(size):
            z = math.sqrt(x) + math.sqrt(y)
main()

2. Reduce Attribute Access

2.1 Avoid Module and Function Attribute Access

Importing specific functions (e.g., from math import sqrt ) eliminates the overhead of attribute lookups.

# Not recommended – attribute access (14.5 s)
import math

def compute_sqrt(size):
    result = []
    for i in range(size):
        result.append(math.sqrt(i))
    return result

# Recommended – local reference (10.9 s)
from math import sqrt

def compute_sqrt(size):
    result = []
    for i in range(size):
        result.append(sqrt(i))
    return result

2.2 Avoid Class Attribute Access

Assign frequently used class attributes to local variables to avoid repeated self. lookups.

# Not recommended – class attribute (10.4 s)
class Demo:
    def __init__(self, value):
        self._value = value
    def compute(self, size):
        result = []
        for _ in range(size):
            result.append(math.sqrt(self._value))
        return result

# Recommended – local variable (8.0 s)
class Demo:
    def __init__(self, value):
        self._value = value
    def compute(self, size):
        sqrt = math.sqrt
        val = self._value
        result = []
        for _ in range(size):
            result.append(sqrt(val))
        return result

3. Avoid Unnecessary Abstraction

Eliminate property getters/setters and decorators that add overhead when simple attributes suffice.

# Not recommended – property (0.55 s)
class Demo:
    def __init__(self, value):
        self._value = value
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, x):
        self._value = x

# Recommended – direct attribute (0.33 s)
class Demo:
    def __init__(self, value):
        self.value = value

4. Avoid Unnecessary Data Copying

Do not create intermediate lists when a single comprehension suffices, and avoid deep copies unless required.

# Not recommended – extra list (6.5 s)
value = range(size)
value_list = [x for x in value]
square_list = [x*x for x in value_list]

# Recommended – single comprehension (4.8 s)
value = range(size)
square_list = [x*x for x in value]

# Swap without temporary variable (0.06 s)
a, b = b, a

5. Leverage Short‑Circuit Logic

Place the most likely true condition first in or expressions and the most likely false condition first in and expressions to reduce evaluation cost.

# Recommended – short‑circuit (0.03 s)
if token[-1] == '.' and token in abbreviations:
    result += token

6. Loop Optimizations

6.1 Use for Instead of while

for loops are faster in CPython.

# Not recommended – while (6.7 s)
i = 0
while i < size:
    sum_ += i
    i += 1

# Recommended – for (4.3 s)
for i in range(size):
    sum_ += i

6.2 Implicit for Loops

Use built‑in functions like sum() that internally iterate.

# Recommended – implicit for (1.7 s)
def compute_sum(size):
    return sum(range(size))

6.3 Reduce Inner Loop Computations

Cache results of expensive operations outside inner loops.

# Not recommended – repeated sqrt (12.8 s)
for x in range(size):
    for y in range(size):
        z = sqrt(x) + sqrt(y)

# Recommended – cache sqrt(x) (7.0 s)
for x in range(size):
    sqrt_x = sqrt(x)
    for y in range(size):
        z = sqrt_x + sqrt(y)

7. Use numba.jit for JIT Compilation

Applying @numba.jit can dramatically speed up numeric loops.

# JIT‑compiled sum (0.62 s)
import numba

@numba.jit
def compute_sum(size):
    total = 0
    for i in range(size):
        total += i
    return total

8. Choose Appropriate Data Structures

Prefer built‑in containers ( list , dict , set ) which are C‑implemented; for frequent insert/delete use collections.deque , for fast look‑ups use bisect , and for min/max retrieval use heapq .

PerformanceOptimizationBest PracticescodeNumba
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

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.