How to sleep in Python

Learn how to pause your Python script. Explore methods, tips, real-world uses, and common error fixes for sleeping in Python.

How to sleep in Python
Published on: 
Fri
Feb 13, 2026
Updated on: 
Mon
Apr 13, 2026
The Replit Team

Pausing a Python script is a common requirement for tasks like rate limits or process synchronization. The time.sleep() function provides a simple way to halt execution for a specified duration.

In this article, you'll explore techniques to use time.sleep() effectively. You will find practical tips, see real-world applications, and get advice on debugging to master script execution control in your projects.

Using time.sleep() for basic pauses

import time

print("Going to sleep for 2 seconds...")
time.sleep(2)
print("Woke up!")--OUTPUT--Going to sleep for 2 seconds...
Woke up!

To pause the script, you first need to import Python's built-in time module. This gives you access to its time-related functions. The key function here is time.sleep(), which suspends the execution of your script for a specified duration.

  • The function takes one argument: the duration of the pause in seconds.
  • In the example, time.sleep(2) blocks the script for two full seconds before execution continues.
  • You can also pass a float, like time.sleep(0.5), for sub-second delays.

Common sleep variations

Beyond the straightforward time.sleep(), Python offers more sophisticated tools for managing pauses, especially in asynchronous or multi-threaded applications.

Using asyncio.sleep() for asynchronous code

import asyncio

async def main():
print("Going to sleep asynchronously...")
await asyncio.sleep(1)
print("Async sleep completed!")

asyncio.run(main())--OUTPUT--Going to sleep asynchronously...
Async sleep completed!

For asynchronous code, using time.sleep() is a no-go because it freezes the entire program. Instead, you'll use asyncio.sleep(). This function is designed specifically for asynchronous environments and works with the async and await keywords to pause execution without blocking other operations.

  • The key difference is that asyncio.sleep() is non-blocking. It pauses the current task but allows Python's event loop to run other tasks in the meantime—making it essential for building responsive applications.

Using threading.Timer for non-blocking sleep

import threading
import time

def wake_up():
print("Timer completed!")

print("Starting a 2-second timer...")
timer = threading.Timer(2.0, wake_up)
timer.start()
print("Main thread continues running...")
time.sleep(2.5) # Wait for timer to complete--OUTPUT--Starting a 2-second timer...
Main thread continues running...
Timer completed!

For multi-threaded applications where you can't afford to block the main program, you can use threading.Timer. It schedules a function to run on a new thread after a set delay, which lets your main script continue its work without pausing.

  • The threading.Timer(2.0, wake_up) object prepares the wake_up function to run after a two-second delay.
  • Once you call timer.start(), the timer begins in the background. The main thread isn't blocked and proceeds immediately to the next line of code.

Using threading.Event for interruptible sleep

import threading
import time

event = threading.Event()
print("Sleeping until event is set (max 3 seconds)...")
is_set = event.wait(timeout=3)
print(f"Wait completed: event was {'set' if is_set else 'not set'}")--OUTPUT--Sleeping until event is set (max 3 seconds)...
Wait completed: event was not set

For a more flexible, interruptible pause, you can use threading.Event. It's a synchronization tool that lets one thread signal an event to other threads. This is perfect for situations where you need to wait for something to happen but also want to avoid getting stuck forever.

  • The event.wait() method pauses the thread until another thread calls event.set().
  • By adding a timeout, like event.wait(timeout=3), you set a maximum wait time.
  • The method returns True if the event was set or False if it timed out, so your code knows why it woke up.

Advanced sleep techniques

You can also embed sleep logic into more sophisticated structures, such as context managers and decorators, or manage timeouts with the low-level signal module.

Creating a sleep context manager

import time
from contextlib import contextmanager

@contextmanager
def timed_execution(seconds):
yield
time.sleep(seconds)

with timed_execution(1):
print("This code executes immediately")
print("This code executes after the sleep")--OUTPUT--This code executes immediately
This code executes after the sleep

A context manager offers a clean way to wrap a block of code, and the @contextmanager decorator makes creating one simple. In this example, the code inside the with block runs immediately. It's only after that block finishes that the time.sleep() function is called, pausing the script.

  • The yield keyword is the pivot point. Code inside the with statement executes where yield is placed.
  • The code after yield—in this case, time.sleep(seconds)—runs automatically upon exiting the with block.

Implementing a sleep decorator

import time
import functools

def sleep_after(seconds):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
time.sleep(seconds)
return result
return wrapper
return decorator

@sleep_after(1)
def greet():
return "Hello"

print(greet())
print("Printed after sleep")--OUTPUT--Hello
Printed after sleep

A decorator is a clean way to add extra behavior to a function without modifying its source code. The @sleep_after(1) decorator wraps the greet() function, but with a twist—it applies the pause after the function has already run and returned its result.

  • When greet() is called, it executes immediately.
  • The decorator then calls time.sleep(1) before the program proceeds.
  • This pattern is perfect for tasks like rate-limiting, where you need a delay between consecutive function calls.

Using signal module for timeout control

import signal
import time

def timeout_handler(signum, frame):
raise TimeoutError("Operation timed out")

signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(2) # Set alarm for 2 seconds

try:
print("Starting long operation...")
time.sleep(3) # This will be interrupted
print("This won't be printed")
except TimeoutError as e:
print(e)--OUTPUT--Starting long operation...
Operation timed out

The signal module offers a powerful, low-level way to enforce time limits, especially on blocking operations. It works by using system signals to interrupt your program's execution. This approach is particularly useful for operations that don't have a built-in timeout mechanism.

  • You first register a handler function using signal.signal() to respond to a specific signal like SIGALRM.
  • Next, signal.alarm() schedules that signal to be sent after a set number of seconds.
  • When the alarm triggers, your handler runs. In this example, it raises a TimeoutError to break out of the long-running task.

Move faster with Replit

Replit is an AI-powered development platform where all Python dependencies come pre-installed, so you can skip setup and start coding instantly. Instead of piecing together techniques like time.sleep(), you can use Agent 4 to build complete applications from the ground up.

Describe the app you want to build, and the Agent will take it from an idea to a working product. Here are a few examples of what you could create:

  • An API scraper that automatically adds delays with time.sleep() to respect rate limits.
  • A background task scheduler that uses threading.Timer to send a notification after a specific interval.
  • A monitoring utility that polls a service endpoint every few seconds, using threading.Event to wait for a status change or timeout.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

While pausing scripts is useful, you'll often run into a few common pitfalls that can trip up your code.

Forgetting to use await with asyncio.sleep()

A frequent mistake in asynchronous code is calling asyncio.sleep() without the await keyword. Doing so doesn't actually pause your program; it just creates a coroutine object and moves on, which means the intended delay never happens.

  • Remember that asyncio.sleep() is a coroutine. You must use await asyncio.sleep() inside an async function to schedule the pause and yield control back to the event loop.

Handling interruptions during time.sleep()

The time.sleep() function isn't invincible—it can be interrupted by system signals. The most common example is when a user presses Ctrl+C, which sends a SIGINT signal and raises a KeyboardInterrupt exception, cutting the sleep short.

  • To prevent your script from crashing unexpectedly, you can wrap the sleep call in a try...except KeyboardInterrupt block. This allows you to catch the interruption and perform any necessary cleanup for a graceful exit.

Inefficient sleeping in loops

Using a fixed time.sleep() inside a loop for polling can lead to timing inaccuracies. If your loop's task takes 0.5 seconds and you sleep for 1 second, the total cycle time becomes 1.5 seconds, causing your timing to drift with each iteration.

  • A more robust approach is to calculate the time remaining until the next desired execution. By subtracting the task's execution time from your target interval, you can sleep for the precise duration needed to maintain a consistent rhythm.

Forgetting to use await with asyncio.sleep()

It's easy to forget the await keyword when using asyncio.sleep(), creating a bug that's hard to spot. The script will execute without crashing, but the delay you wanted is silently skipped, potentially causing race conditions. See this error in action below.

import asyncio

async def task():
print("Starting task...")
asyncio.sleep(1) # Missing await!
print("Task completed!")

asyncio.run(task())

Without await, the asyncio.sleep(1) call creates a coroutine but never actually runs it. As a result, the script doesn't pause and prints both messages back-to-back. See how a small change fixes this issue below.

import asyncio

async def task():
print("Starting task...")
await asyncio.sleep(1) # Added await
print("Task completed!")

asyncio.run(task())

By adding the await keyword, you correctly pause the coroutine. This signals Python's event loop to suspend the task function for one second before resuming, ensuring "Task completed!" prints only after the delay. Always use await with asyncio.sleep() inside any async function to create a non-blocking pause.

Handling interruptions during time.sleep()

When a user presses Ctrl+C, it sends a KeyboardInterrupt that can stop time.sleep() mid-pause. You can catch this with a try...except block to avoid a crash. The example below shows exactly how your script responds to an interruption.

import time

print("Starting a long sleep (10 seconds)...")
try:
time.sleep(10) # Blocks for 10 seconds
print("Sleep completed")
except KeyboardInterrupt:
print("Sleep was interrupted") # Won't execute immediately

While the try...except block catches the KeyboardInterrupt, the script still terminates immediately. This abrupt exit can skip important cleanup tasks. See how to handle this more gracefully in the code below.

import time

print("Starting a long sleep (10 seconds)...")
try:
for _ in range(10):
time.sleep(1) # Sleep in smaller chunks
print("Sleep completed")
except KeyboardInterrupt:
print("Sleep was interrupted") # Executes sooner

By breaking a long pause into smaller chunks inside a loop, like time.sleep(1), your script becomes far more responsive. If a user triggers a KeyboardInterrupt by pressing Ctrl+C, the exception is caught much sooner—right after the current one-second interval finishes.

This allows your cleanup code in the except block to run almost immediately. It’s a simple change that ensures a graceful shutdown instead of an abrupt crash, giving your script time to save its state or close resources properly.

Inefficient sleeping in loops

Polling with a fixed time.sleep() in a loop often creates timing drift. The task's own execution time adds to the pause, making each cycle longer than intended. The code below demonstrates how this seemingly small inaccuracy can quickly accumulate.

import time

items = ["item1", "item2", "item3", "item4", "item5"]
for item in items:
process_time = 0.1 # Time to process each item
time.sleep(1) # Sleep 1 second between each item
print(f"Processed {item}")

Each loop cycle actually takes 1.1 seconds because the task's 0.1-second execution time adds to the one-second pause. This cumulative delay makes the timing drift. The following example shows how to compensate for this inaccuracy.

import time

items = ["item1", "item2", "item3", "item4", "item5"]
for item in items:
start = time.time()
process_time = 0.1 # Time to process each item

elapsed = time.time() - start
sleep_time = max(0, 1 - elapsed)
time.sleep(sleep_time)

print(f"Processed {item}")

To fix timing drift, you can calculate the sleep duration dynamically. Record the start time with time.time() before your task runs. After the task finishes, subtract its execution time from your target interval. Sleeping for the remaining time ensures each loop cycle stays on a consistent rhythm. This approach is crucial for any polling task where timing precision is important, preventing the small delays from accumulating over time.

Real-world applications

Now that you know the pitfalls, you can see how time.sleep() powers practical tools for API rate limiting or creating simple countdowns.

Creating a countdown timer with time.sleep()

You can build a simple countdown timer by placing time.sleep() inside a loop, creating a pause between each number displayed.

import time

def countdown(seconds):
print(f"Starting countdown: {seconds} seconds")
for remaining in range(seconds, 0, -2):
print(f"{remaining} seconds left")
time.sleep(2)
print("Countdown complete!")

countdown(6)

This countdown function creates a timed sequence using a for loop. The range(seconds, 0, -2) call is what drives the timer, generating numbers that start from the initial value and step down by two until they reach zero.

  • In each iteration, the script prints the current number.
  • After printing, time.sleep(2) pauses the program for two full seconds.

This combination of looping and sleeping results in a simple, predictable timer that executes in discrete steps before printing its completion message.

Implementing API rate limiting with time.sleep()

Using time.sleep() is a straightforward way to implement rate limiting, ensuring your script respects an API's rules by pausing between requests.

import time

def fetch_with_rate_limit(urls, requests_per_second=1):
interval = 1.0 / requests_per_second

for i, url in enumerate(urls):
if i > 0: # Don't sleep before the first request
print(f"Rate limiting: waiting {interval:.1f} seconds...")
time.sleep(interval)
print(f"Fetching: {url}")

urls = ["https://api.example.com/1", "https://api.example.com/2"]
fetch_with_rate_limit(urls)

The fetch_with_rate_limit function manages how frequently your script processes a list of URLs. It calculates the required interval based on the requests_per_second argument, creating a specific delay between each action.

  • The loop uses enumerate to track the request count, and the if i > 0: condition prevents a pause before the first URL is fetched.
  • This ensures the delay from time.sleep() only occurs between subsequent requests, making the process efficient by avoiding an unnecessary wait at the start.

Get started with Replit

Put these techniques into practice and build a real tool. Tell Replit Agent to “build a web scraper that respects rate limits” or “create a terminal pomodoro timer using time.sleep()”.

The Agent writes the code, tests for errors, and deploys your app directly from your browser. Start building with Replit.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.