How to Repeat Code, Functions and Values in Python

Python has no built-in repeat() function, and what you need depends on what you are repeating. To repeat code a fixed number of times, use for _ in range(n). To repeat it until something happens, use while True with a break, because Python has no repeat-until loop. To repeat a value, multiply it: "ab" * 3 or [0] * 5. And for repeated values in an iterator or an array there are itertools.repeat() and numpy.repeat(). This guide runs all of them, and shows where each one goes wrong.

Every example was run with Python 3.12.5 and NumPy 2.5.3 in the Windows Command Prompt, and the output shown is the real output. Reference: itertools.repeat() in the Python documentation.

Repeat code, a string or a list in Python

Three different jobs, three one-liners:

# repeat a block of code 3 times
for _ in range(3):
    print("Backing up the database...")

# repeat a string
print("-" * 30)
print("ha" * 3)

# repeat a list
print([0] * 5)
print(["Austin", "Denver"] * 2)

Output:

Backing up the database...
Backing up the database...
Backing up the database...
------------------------------
hahaha
[0, 0, 0, 0, 0]
['Austin', 'Denver', 'Austin', 'Denver']
Command Prompt output of a Python for loop repeating a message three times, a divider line made with the star operator, and a repeated string and list
for _ in range(3) repeats the block; * repeats the value.
What you want to repeatUseExample
A block of code, n timesfor _ in range(n)for _ in range(3): backup()
A block until something is truewhile True + breakwhile True: ... if done: break
A block while something is truewhile conditionwhile queue: process(queue.pop(0))
A string or a listthe * operator"-" * 30, [0] * 5
A value as an iteratoritertools.repeat(value, n)repeat("pending", 4)
Values inside an arraynumpy.repeat()np.repeat(a, 2)

The underscore in for _ in range(3) is a normal variable name that says “I am not using this”. If you do need the number, name it: our guide to for i in range() in Python covers that side.

Repeat a function in Python

There is no special syntax for repeating a function call: you call it inside a loop. Keep the results with a list comprehension, and use itertools.repeat() when you want to pass the same argument to every item in a list through map():

import itertools

def send_reminder(customer: str) -> str:
    return f"reminder sent to {customer}"

# repeat a function call for each item
for customer in ("Emma", "Michael", "Olivia"):
    print(send_reminder(customer))

# repeat the same call a fixed number of times and keep the results
results = [send_reminder("Emma") for _ in range(2)]
print(results)

# repeat one function over many arguments with the SAME extra argument
print(list(map(pow, range(4), itertools.repeat(2))))    # square each number

def repeat_call(func, times, *args):
    """Call func(*args) a number of times and return every result."""
    return [func(*args) for _ in range(times)]

print(repeat_call(send_reminder, 3, "Noah"))

Output:

reminder sent to Emma
reminder sent to Michael
reminder sent to Olivia
['reminder sent to Emma', 'reminder sent to Emma']
[0, 1, 4, 9]
['reminder sent to Noah', 'reminder sent to Noah', 'reminder sent to Noah']

The little repeat_call helper is worth having in a utilities module when you genuinely call the same function many times, but a plain loop is usually clearer.

Repeat until something happens

Python has no repeat ... until and no do ... while. The standard replacement is while True with a break at the point where you want to stop, which runs the body at least once. When the test belongs at the top instead, a normal while condition is better, as our for loop versus while loop comparison explains:

# Python has no repeat...until or do...while, so use while True and break
attempt = 0
while True:
    attempt += 1
    print("checking the queue, attempt", attempt)
    if attempt == 3:            # the "until" condition
        print("queue is empty, stopping")
        break

# the same loop written the other way round
queue = ["job-1", "job-2", "job-3"]
while queue:                    # repeat while there is work left
    print("processing", queue.pop(0))

# repeat until the input is valid (the inputs are scripted here so it can run)
answers = iter(["maybe", "later", "yes"])
while (answer := next(answers)) not in {"yes", "no"}:
    print(f"'{answer}' is not valid, asking again")
print("accepted:", answer)

Output:

checking the queue, attempt 1
checking the queue, attempt 2
checking the queue, attempt 3
queue is empty, stopping
processing job-1
processing job-2
processing job-3
'maybe' is not valid, asking again
'later' is not valid, asking again
accepted: yes
Command Prompt output showing a Python while True loop breaking on the third attempt, a queue being drained, and an input validation loop
Three shapes of the same idea: while True + break, while queue, and a validation loop.

The third example uses the walrus operator, :=, to read a value and test it in one line. Swap the scripted answers for input() and it becomes the loop that keeps asking until the user types something valid; continue skips the rest of a pass without leaving the loop.

Repeat a function until it succeeds

The most common real-world repeat is a retry: call something that talks to the network, and if it fails, wait a moment and try again. This one fails twice before it works, and backs off a little longer after each failure:

import time

calls = 0

def unstable_api() -> str:
    """Fails twice, then works."""
    global calls
    calls += 1
    if calls < 3:
        raise ConnectionError(f"timeout on call {calls}")
    return "200 OK"

def with_retry(func, attempts: int = 5, delay: float = 0.05):
    """Repeat a function until it succeeds, waiting longer after each failure."""
    for attempt in range(1, attempts + 1):
        try:
            return func()
        except ConnectionError as error:
            print(f"attempt {attempt} failed: {error}")
            if attempt == attempts:
                raise
            time.sleep(delay * attempt)      # back off a little longer each time

print("result:", with_retry(unstable_api))
print("total calls:", calls)

Output:

attempt 1 failed: timeout on call 1
attempt 2 failed: timeout on call 2
result: 200 OK
total calls: 3
Command Prompt output showing a Python retry helper repeating a failing API call until the third attempt succeeds
Two failures, a longer pause each time, then 200 OK on the third attempt.

itertools.repeat(): a value, over and over

itertools.repeat() produces the same value as many times as you ask, or forever if you leave the count out. It does not build a list, so an infinite repeat costs nothing until you consume it. It is also the fastest way to run a loop a fixed number of times when the counter is not used:

import itertools
import timeit

print(list(itertools.repeat("pending", 4)))          # a fixed number of copies

counter = itertools.repeat("tick")                    # no count: infinite
print(list(itertools.islice(counter, 3)))

print(list(zip(["Emma", "Michael"], itertools.repeat("active"))))

n = 1_000_000
loop_range = timeit.timeit("for _ in range(n): pass", globals={"n": n}, number=3) / 3
loop_repeat = timeit.timeit("for _ in itertools.repeat(None, n): pass",
                            globals={"n": n, "itertools": itertools}, number=3) / 3
print(f"range(n):                {loop_range * 1000:6.1f} ms")
print(f"itertools.repeat(None, n):{loop_repeat * 1000:6.1f} ms")

Output:

['pending', 'pending', 'pending', 'pending']
['tick', 'tick', 'tick']
[('Emma', 'active'), ('Michael', 'active')]
range(n):                  10.6 ms
itertools.repeat(None, n):   4.5 ms
Command Prompt output of itertools repeat producing four copies, an infinite iterator sliced to three, zip pairing, and a timing comparison against range
The same million iterations: looping over itertools.repeat(None, n) finishes noticeably sooner than over range(n).

The gap moves between runs and Python versions, and it only matters at all in a tight loop that does nothing else, so do not rewrite your code for it. It is handy to know why you sometimes see for _ in repeat(None, n) in library source.

numpy.repeat() and numpy.tile()

For arrays there are two different repeats, and picking the wrong one is a classic bug. np.repeat() repeats each element in place; np.tile() repeats the whole array end to end. With a list of counts you can repeat each element a different number of times, and axis chooses rows or columns:

import numpy as np

values = np.array([1, 2, 3])

print(np.repeat(values, 2))          # each element twice, in place
print(np.tile(values, 2))            # the whole array twice, end to end
print(np.repeat(values, [1, 2, 3]))  # a different count per element

matrix = np.array([[1, 2], [3, 4]])
print(np.repeat(matrix, 2, axis=0))  # repeat rows
print(np.repeat(matrix, 2, axis=1))  # repeat columns

Output:

[1 1 2 2 3 3]
[1 2 3 1 2 3]
[1 2 2 3 3 3]
[[1 2]
 [1 2]
 [3 4]
 [3 4]]
[[1 1 2 2]
 [3 3 4 4]]

Mistakes to avoid when repeating

The big one is repeating a list that contains lists. [[0] * 3] * 3 makes three references to the same row, so changing one changes all of them. Build the rows separately with a comprehension. The other traps are smaller: the repeat count must be an integer, zero or a negative count gives you an empty result rather than an error, and an iterator from a repeated value is used up after a single pass:

# repeating a list of lists copies the REFERENCE, not the row
grid = [[0] * 3] * 3
grid[0][0] = 9
print(grid)                       # every row changed

grid = [[0] * 3 for _ in range(3)]    # build each row separately
grid[0][0] = 9
print(grid)

try:
    print("ab" * 2.0)             # the count has to be an int
except TypeError as error:
    print("TypeError:", error)

print("ab" * 0, "|", "ab" * -1, "| both are empty strings")

import itertools
values = itertools.repeat("x", 3)
print(list(values), list(values))  # an iterator is used up after one pass

Output:

[[9, 0, 0], [9, 0, 0], [9, 0, 0]]
[[9, 0, 0], [0, 0, 0], [0, 0, 0]]
TypeError: can't multiply sequence by non-int of type 'float'
 |  | both are empty strings
['x', 'x', 'x'] []
Command Prompt output showing a Python grid built with list multiplication sharing rows, a TypeError for a float repeat count, and an exhausted iterator
The first grid changed every row; the comprehension version changed only one.

More Python loop and sequence guides worth reading:

Frequently asked questions

Is there a repeat() function in Python?

Not as a built-in. Use for _ in range(n) for code, * for strings and lists, itertools.repeat() for an iterator, or numpy.repeat() for arrays.

How do I repeat a block of code n times in Python?

for _ in range(n): followed by the indented block. The underscore is a normal variable that signals the counter is not used.

How do I repeat a function in Python?

Call it inside a loop: for _ in range(3): send_reminder(). Use a list comprehension when you want to keep every return value.

How do I write repeat until in Python?

Python has no repeat-until or do-while. Use while True: with the test and a break at the end of the body, so the block always runs once.

How do I repeat a string a number of times?

Multiply it: "ab" * 3 gives 'ababab'. A count of 0 or a negative number gives an empty string.

What is the difference between numpy.repeat() and numpy.tile()?

np.repeat([1, 2, 3], 2) gives [1 1 2 2 3 3], repeating each element. np.tile([1, 2, 3], 2) gives [1 2 3 1 2 3], repeating the whole array.

Why did changing one row of my repeated list change them all?

[[0] * 3] * 3 repeats a reference to one list. Use [[0] * 3 for _ in range(3)] so each row is its own object.