Python itertools.repeat: Syntax and Use Cases
python itertools repeat: Learn how itertools.repeat creates infinite or bounded sequences, its memory efficiency, and when to use it over list multiplication.
python itertools repeat requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need an iterator that yields the same value many times, itertools.repeat is the direct tool. It accepts a value and an optional count, and returns an iterator that produces that value either forever or exactly count times. Here is the minimal syntax:
from itertools import repeat # Infinite iterator infinite = repeat(42) # Bounded iterator bounded = repeat("x", 5)
The first iterator yields 42 indefinitely. The second yields the string "x" five times and then stops. Because repeat returns a lazy iterator, it does not allocate a list of repeated values up front. That behavior matters when the repetition count is large or unknown.
What itertools.repeat Returns
repeat is a factory function in the itertools module. It returns an iterator object, not a list. The iterator is lazy: it produces values one at a time as the consumer requests them. For an infinite repetition, the iterator never raises StopIteration. For a finite count, it raises StopIteration after yielding the specified number of items.
The returned iterator is a distinct object each time repeat is called. Two separate calls to repeat(5) produce two independent iterators. They do not share state. This is consistent with other itertools functions, which are designed to be composed and consumed once.
Basic Syntax and Parameters
repeat(object, times=None) takes two arguments:
object: the value to yield repeatedly. It can be any Python object, including mutable ones. Note that the same object reference is returned each time, not a copy.times: an integer specifying how many times to yield the object. If omitted orNone, the iterator is infinite.
The times argument must be a non-negative integer. Passing a negative number raises ValueError. Passing a non-integer like a float raises TypeError. The value itself is not copied; each iteration yields the same object. If you need independent copies, you must handle that yourself.
Common Use Cases in Real Code
One common use is pairing a constant value with another iterator using zip. For example, to assign a default status to a list of records:
from itertools import repeat records = ["alpha", "beta", "gamma"] status = "pending" for record, state in zip(records, repeat(status)): print(record, state)
This is equivalent to zip(records, [status] * len(records)), but it avoids creating a temporary list. The repeat iterator is infinite, so zip stops when the shorter input is exhausted.
Another use is in map when you want to apply a function that requires two arguments, where one argument is constant:
from itertools import repeat def add_tax(price, rate): return price * (1 + rate) prices = [100, 200, 300] taxed = list(map(add_tax, prices, repeat(0.2)))
Here repeat(0.2) supplies the same tax rate to every call. Without repeat, you would need a list of repeated rates or a lambda with a default argument.
repeat also appears in algorithms that need a fixed number of identical steps, such as retry loops or initialization sequences.
Memory and Performance Characteristics
The main advantage of repeat is memory efficiency. It does not precompute a list of repeated values. For large times values, this can avoid significant allocation. For example, repeat(0, 10**9) uses constant memory, while [0] * 10**9 creates a list of one billion references, consuming several gigabytes.
The iterator also avoids the overhead of constructing a generator function or a lambda. A generator expression like (value for _ in range(n)) has slightly more per-iteration overhead because it maintains a loop counter and a generator frame. repeat is implemented in C and is generally faster for simple repetitions.
However, repeat is not always the right choice. If you need to index into the sequence or pass it to a function that requires a list, you must materialize it. Materializing with list(repeat(value, n)) is equivalent to [value] * n in terms of memory usage, but the list multiplication syntax is more direct and often clearer.
Comparing with List Multiplication and Generator Expressions
The table below summarizes the differences:
| Approach | Lazy | Memory Usage | Speed | Readability |
|---|---|---|---|---|
repeat(value, n) | Yes | O(1) | Fast (C implementation) | Clear when used with zip or map |
[value] * n | No | O(n) | Very fast for list creation | Simple for small, known sizes |
(value for _ in range(n)) | Yes | O(1) | Slower due to Python loop | More verbose |
Use repeat when you are composing iterators and do not need a concrete list. Use list multiplication when you actually need a list and the size is small enough to fit in memory. Use a generator expression when you need a custom pattern or a non-constant value.
Edge Cases and Potential Pitfalls
Because repeat returns the same object reference each time, mutating the yielded object affects all subsequent yields. For example:
from itertools import repeat items = list(repeat([], 3)) items[0].append(1) print(items) # [[1], [1], [1]]
If you need independent copies, use a list comprehension or a generator that creates a new object each time.
Another pitfall is using an infinite repeat without a terminating condition. If you pass it to list() or iterate over it without break, the program will hang. Always ensure that an infinite repeat is paired with a finite iterator or an explicit exit condition.
The times parameter must be an integer. Passing None is allowed and means infinite. Passing 0 yields an empty iterator, which is valid but rarely useful.
When to Prefer itertools.repeat
Choose itertools.repeat when you need a constant value in a stream of operations, especially in combination with zip, map, or other itertools functions. It is also the right choice when the repetition count is very large and you want to avoid allocating a list. For simple cases where you need a list of repeated values and the size is small, [value] * n is more readable and equally fast. For patterns that involve changing values, use a generator expression instead.
The key is to match the tool to the data flow. repeat shines in lazy composition, where memory and iteration overhead matter more than the convenience of a concrete list.