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']
for _ in range(3) repeats the block; * repeats the value.| What you want to repeat | Use | Example |
|---|---|---|
| A block of code, n times | for _ in range(n) | for _ in range(3): backup() |
| A block until something is true | while True + break | while True: ... if done: break |
| A block while something is true | while condition | while queue: process(queue.pop(0)) |
| A string or a list | the * operator | "-" * 30, [0] * 5 |
| A value as an iterator | itertools.repeat(value, n) | repeat("pending", 4) |
| Values inside an array | numpy.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
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
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
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'] []
More Python loop and sequence guides worth reading:
- for i in range() in Python
- for loop vs while loop
- Loop through a list in Python
- continue in a while loop
- Create a string of n characters
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.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn