sum() Function Complexity¶
The sum() function adds the items of an iterable to a start value, which
defaults to 0. It makes one pass and one + per item, so the cost is the
number of items times the cost of one addition. That addition is constant for
machine-word integers and floats, linear in the width for wider integers, and
a copy of the whole running total for lists and tuples.
Complexity Analysis¶
Let n be the number of items. Space excludes the iterable itself and
start.
| Case | Time | Space | Notes |
|---|---|---|---|
Exact int and bool items, running total within a machine word |
O(n) | O(1) | Accumulated in a C integer |
Wider int items |
O(n·(w + log n)) | O(w + log n) | w = bits of the widest item or start; each + copies the running total, which is at most log n bits wider |
float and complex items |
O(n) | O(1) | float is accumulated in a C double, compensated from Python 3.12 |
list or tuple items with a matching start |
O(n·N) | O(N) | N = total elements, start included; each + copies the whole running total. Use itertools.chain |
str, bytes, bytearray |
— | — | Such a start raises TypeError; without one, 0 + "a" raises. Use ''.join() |
| Any other type | O(n·a) | O(1) auxiliary | a = cost of one +, done once per item; sum() holds only the running total |
Basic Usage¶
Summing Numbers¶
# O(n) - single pass through items
numbers = [1, 2, 3, 4, 5]
total = sum(numbers) # 15
# Works with any numeric iterable
total = sum([1.5, 2.5, 3.0]) # 7.0
total = sum(range(100)) # 4950
total = sum((10, 20, 30)) # 60
# With start value
total = sum([1, 2, 3], start=100) # 106
Generator Expressions¶
# O(n) - evaluates generator once
total = sum(x for x in range(10)) # 45
total = sum(x**2 for x in range(5)) # 30
# More efficient than creating list first
total = sum(x for x in range(1000000)) # O(n) time, O(1) space
# vs creating list first
total = sum([x for x in range(1000000)]) # O(n) time, O(n) space
Common Patterns¶
Counting Items¶
# O(n) time, O(n) space - list comprehension
count = sum([1 for x in range(100) if x % 2 == 0]) # 50 even numbers
# Better: sum with boolean (True=1, False=0) - O(n) time, O(1) space
count = sum(x % 2 == 0 for x in range(100)) # 50 even numbers
Computing Statistics¶
# O(n) - one pass for the sum, len() is O(1)
numbers = [1, 2, 3, 4, 5]
average = sum(numbers) / len(numbers) # 3.0
# Two passes - counting by iterating again
average = sum(numbers) / sum(1 for _ in numbers) # 3.0
Flattening Lists¶
# O(n*N) - n = number of lists, N = total items
# Each + copies every item accumulated so far
nested = [[1, 2], [3, 4], [5, 6]]
flat = sum(nested, []) # [1, 2, 3, 4, 5, 6] - avoid this!
# Better approaches:
# O(N) - each item copied once
from itertools import chain
flat = list(chain.from_iterable(nested))
# O(N) - single pass, no repeated copying
flat = [item for sublist in nested for item in sublist]
Performance Considerations¶
Wide Integers¶
# O(n) - machine-word ints are accumulated in C
total = sum(range(1000)) # 499500
# O(n*(w + log n)) - each + copies the running total, w = bits per item
wide = [10**300] * 1000
total = sum(wide) # 1000 * 10**300
Why Not for Strings¶
# ❌ sum() refuses a str start outright
try:
text = sum(["a", "b", "c"], "")
except TypeError:
pass # sum() can't sum strings [use ''.join(seq) instead]
# ❌ And without a start, the first + is 0 + "a"
try:
text = sum(["a", "b", "c"])
except TypeError:
pass # unsupported operand type(s) for +: 'int' and 'str'
# ✅ O(total length) with join
text = "".join(["a", "b", "c", "d", "e"]) # "abcde"
The same applies to bytes and bytearray: use b"".join().
Working with Custom Objects¶
Custom add Method¶
# O(n*m) where m = time for __add__
class Vector:
def __init__(self, *components):
self.components = components
def __add__(self, other):
# O(m) where m = number of components
return Vector(*(a + b for a, b in zip(self.components, other.components)))
def __repr__(self):
return f"Vector{self.components}"
vectors = [Vector(1, 2), Vector(3, 4), Vector(5, 6)]
result = sum(vectors, Vector(0, 0)) # Vector(9, 12)
# Complexity: O(n*m) where n=3 vectors, m=2 components
Default Start Value¶
# The first + is start + item, and start defaults to 0
result = sum([1, 2, 3]) # 6
result = sum([1, 2, 3], start=10) # 16
# Without a start, the first item is added to 0, so the type needs __radd__
class Vector:
def __init__(self, *components):
self.components = components
def __add__(self, other):
return Vector(*(a + b for a, b in zip(self.components, other.components)))
def __radd__(self, other):
return self if other == 0 else NotImplemented
result = sum([Vector(1, 2), Vector(3, 4)]) # Vector(4, 6), no start needed
Comparison with Alternatives¶
vs Loop¶
# sum() - O(n)
numbers = list(range(10000))
total = sum(numbers)
# Manual loop - O(n), same bound
total = 0
for num in numbers:
total += num
# Both have same complexity, sum() is preferred
vs Accumulate¶
from itertools import accumulate
# sum() - O(n), returns single value
numbers = [1, 2, 3, 4, 5]
total = sum(numbers) # 15
# accumulate - O(n) but returns all intermediate sums
totals = list(accumulate(numbers)) # [1, 3, 6, 10, 15]
vs math.fsum¶
from math import fsum
# Both O(n). fsum() keeps every partial sum exactly; sum() carries
# one compensation term from Python 3.12, and none before it.
values = [0.1] * 10
fsum(values) # 1.0 on every version
sum(values) # 1.0 from 3.12; 0.9999999999999999 before
Best Practices¶
✅ Do:
- Use
sum()for numeric aggregation - Use generator expressions with
sum()for memory efficiency - Use
math.fsum()when float rounding matters
❌ Avoid:
sum(nested_lists, [])- copies the whole running total at every stepsum(strings, "")- raisesTypeError; use"".join()
Related Functions¶
- any() - Check if any item is true
- all() - Check if all items are true
- max() - Find maximum value
- min() - Find minimum value
- math.fsum() - Precise float summation
Version Notes¶
- Python 3.8+:
startcan be passed as a keyword argument - Python 3.12+:
floatitems are summed with Neumaier compensation, sosum([0.1] * 10) == 1.0