Have you ever had one of those days where your code just feels like it’s off to the races? The text blitzes past before you’ve even read it, or your carefully stacked and sequenced steps keep falling over for no good reason.
As devs, we’re normally focused on speeding things up, but in this situation we want to slow them down so our code behaves properly.
The good news is that Python actually has a simple function that does this for us.
The issue of course is knowing how to use it well. So stick with me, and I’ll walk you through what it does and how it works, as well as common mistakes and how to get past them.
Let’s get into it.
Sidenote: If you find any of this confusing, or simply want a deep dive into Python, check out Andrei's Python Coding course taken by 200,000+ people:
It’ll take you from an absolute beginner to understanding everything you need to be hired ASAP.
Alternatively, if you're already pretty good at Python and want to build some interesting and useful projects, why not check out my course on Python Automation:
It'll show you how to automate all of the boring or repetitive tasks in your life - and makes for some pretty standout portfolio projects as well!
With all that out of the way, let's get into this 5-minute tutorial!
At its heart, time.sleep() is Python’s way of pausing whatever it’s doing at the time. You give it a number, and your program waits that many number of seconds before moving on.
It’s kind of like pressing the pause button on Netflix while you go grab your UberEats. The movie hasn’t stopped or returned back to the beginning. It’s just on hold until you want it to start playing again.
Simple enough concept, but why would we want to do this?
Because without pauses, code often runs too fast to be useful. Output can flash by before you can read it, or processes can even break because they didn’t give other systems enough time to respond.
The easiest way to understand all this is to see it in action.
At first glance, time.sleep() looks almost too simple:
You import the time module
Give it a number of seconds to pause for
Then your program pauses for that many seconds before moving on
But the real value is seeing how those pauses change the feel of your code.
For example
Imagine we have a simple line of text: “Hello, is anyone there?”
import time
print("Hello")
time.sleep(2)
print("...is anyone there?")
Be honest now. If you saw that show up in your IDE you would freak out, right?
We can also use timing for more aesthetic uses.
For example
A classic use case for time.sleep() is to create a typewriter effect:
import time
message = "Typing this out..."
for char in message:
print(char, end="", flush=True)
time.sleep(0.1) # short pause between each character
Too fast and the effect disappears, too slow and it becomes frustrating. Somewhere in the middle though, and you get this neat “typing across the screen” feel that makes the output way more engaging.
Pauses can also help make loops seem more realistic.
For example
Imagine you’ve created an app that simulates a temperature sensor:
import time
import random
for i in range(5):
print("Temperature:", random.randint(20, 30))
time.sleep(1) # wait one second between readings
time.sleep() also helps when things go wrong.
For example
Suppose you’re fetching data from the internet and the request fails. Retrying immediately won’t help because the server hasn’t had time to recover.
import time
import requests
for attempt in range(3):
try:
response = requests.get("https://example.com")
print("Success:", response.status_code)
break
except:
print("Request failed, retrying...")
time.sleep(2) # wait 2 seconds before trying again
Handy right?
And then there’s rate-limiting.
Many APIs only allow a certain number of requests per minute, meaning that sending too many requests too fast can get you blocked. However, pausing between requests can be a great way to keep you in the safe zone.
For example
So let’s say we have a server that allows 100 requests per minute - roughly one every 0.6 seconds. To avoid ending up on the API’s “naughty list”, you could simply pick a delay slightly above that threshold.
import time
import requests
urls = ["https://example.com/page1", "https://example.com/page2"]
for url in urls:
response = requests.get(url)
print("Fetched:", url)
time.sleep(1) # pause between requests to stay under the limit
As you can see, time.sleep() can be quite handy. But that being said, there are a few things that tend to trip people up when using it.
Even though time.sleep() is fairly simple in concept, it’s also one of those functions that’s easy to misuse. Here are 3 traps beginners fall into, and how to sidestep them.
One of the easiest things to overlook about time.sleep() is that while it’s waiting, your whole program is frozen. This means Python isn’t secretly doing work in the background. It’s just sitting there, twiddling its thumbs until the timer runs out.
That’s fine for little scripts, but it can cause problems in bigger programs.
For example
Imagine a chatbot that should respond instantly to users. If you drop a time.sleep(5) in the middle of its code, that five-second pause delays everything. So now the bot feels unresponsive, and the user thinks it’s broken.
import time
def greet():
print("Hi there!")
time.sleep(5) # program frozen for 5 seconds
print("How are you?")
print("Starting...")
greet()
print("Done")
When you run this, nothing happens for five seconds after “Hi there!” It looks like the program has stalled, but really it’s just locked up by sleep().
The best practice here is to use time.sleep() for simple scripts, demos, or controlled tasks - basically, scenarios where a hard pause could potentially make sense.
But if on the other hand you need to manage timing in a program that needs to handle multiple tasks simultaneously, you’ll want a non-blocking approach. In modern Python, that usually means async.
For example
Here’s the same idea using asyncio.sleep, which lets other tasks keep running during the pause:
import asyncio
async def greet():
print("Hi there!")
await asyncio.sleep(5) # program can do other work while waiting
print("How are you?")
async def main():
await asyncio.gather(greet(), greet())
asyncio.run(main())
Now both greetings run at the same time, because the pause isn’t blocking the whole program.
The key takeaway: time.sleep() is great when you want everything to stop for a moment. But if your program needs to stay responsive, it’s the wrong tool.
We’ll cover asyncio.sleep more in another post.
Another common pitfall is treating time.sleep() like duct tape and sticking it everywhere to paper over problems.
It can feel easier to just throw in a pause and “hope things are ready” rather than actually check. But that approach is liable to break when you run your program in a real-world environment.
For example
Let’s say you’re waiting for a file to be created:
import time
import os
# Bad approach
time.sleep(5) # just hoping 5 seconds is enough
print("File found:", os.path.exists("output.txt"))
If the file shows up within 5 seconds, you’re fine. But if it takes 6? Your code fails, even though the file did appear eventually. If it’s ready instantly, you wasted 5 seconds doing nothing.
The better approach is to actually check whether the condition is true, looping until it is. That way your program adapts to reality instead of guessing:
import time
import os
# Better approach
while not os.path.exists("output.txt"):
print("Waiting for file...")
time.sleep(1)
print("File found!")
This mistake isn’t just about files. Beginners sometimes use sleep to wait for websites to load, databases to respond, or user input to arrive. It might seem to “work” during testing, but it’s fragile and unreliable.
The best practice is to instead use sleep for pacing, not guessing. If you’re waiting on something external, check its actual status. That way your program stays fast when it can be, and patient when it needs to be.
One thing about time.sleep() is that while your program is paused, it doesn’t really “listen” for anything else. And that includes you trying to stop it!
For example
Let’s say you run this code and then hit Ctrl+C right after “Starting...” shows up:
import time
print("Starting...")
time.sleep(10) # program is stuck here
print("Done")
You might expect the program to quit instantly. But instead, it’s likely to just sit there for the rest of the 10 seconds before finally raising the interrupt, which can feel frustratingly like the program is ignoring you.
This happens because time.sleep() is blocking Python at a low level. It’s not actively checking for signals while it’s sleeping, so your interrupt has to wait until the sleep finishes.
Most of the time this isn’t a huge deal, but it’s worth being aware of. If you find yourself waiting too long to stop a script, try using shorter sleeps in a loop instead of one big one:
import time
print("Starting...")
for _ in range(10): # 10 smaller pauses
time.sleep(1)
print("Done")
The best practice here is simple: When you need long waits, break them into smaller chunks. It gives you more control and makes your program feel less like it’s locked up.
So as you can see, while time.sleep() might be one of Python’s simplest functions, it's also one of the most useful.
Like most tools though, simple or otherwise, it’s easy to misuse. Use it for pacing - not guessing - and be mindful that it blocks everything while it runs. And when you need longer waits, don’t be afraid to break them into smaller pieces so your program stays responsive.
Once you’ve mastered the basics here, you’ll eventually bump into cases where you want to incorporate a pause without freezing your entire program. That’s where async tools like asyncio.sleep or scheduling libraries come in, but those are stories for another guide.
The best way to master those basics, of course, is to actually use the sleep function in your own code. So go ahead and grab one of your own Python projects and try it out for yourself.
Don’t forget, if you want to learn more and dive deep into Python, then be sure to check out Andrei's Complete Python Developer course
It’ll take you from an absolute beginner and teach you everything you need to get hired ASAP and ace the tech interview.
This is the only Python course you need if you want to go from complete Python beginner to getting hired as a Python Developer this year!
Alternatively, if you're already pretty good at Python and want to build some interesting and useful projects, why not check out my course on Python Automation:
It'll show you how to automate all of the boring or repetitive tasks in your life, and makes for some pretty stand out portfolio projects!
Plus, as part of your membership, you'll get access to both of these courses and others, and be able to join me and 1,000s of other people (some who are alumni mentors and others who are taking the same courses that you will be) in the ZTM Discord.
Ask questions, help others, or just network with other Python Developers, students, and tech professionals.
If you enjoyed this post, check out my other Python tutorials: