
The Python pass statement is one of those small but essential keywords that every Python programmer needs to understand. When you are writing code and need a block that does nothing — whether it is an empty function, an empty class, or a placeholder loop body — the pass statement is the answer.
In Python, the syntax requires that every block of code (after a colon) must contain at least one statement. If you try to leave a block completely empty, Python raises an error. The pass statement solves this problem by acting as a null operation — it tells Python "there is nothing to do here, and that is intentional."
def my_function():
pass
The pass keyword does not return any value, does not raise any errors, and does not affect program flow. It is purely a syntax placeholder that keeps your code valid while you build it out.
The Python pass statement is Python's way of saying "do nothing." When the interpreter encounters pass, it executes it and immediately moves on. No side effects, no output, no state changes — nothing at all.
This is different from leaving a comment. A comment is ignored entirely by the interpreter. The pass statement is an actual statement that the interpreter processes, it just happens to have no effect. This distinction matters in places where Python requires a real statement, not just whitespace or a comment.
Consider this scenario: you are designing the structure of a large module. You want to define all your function names and class names upfront before filling in the logic. Without pass, Python would reject every empty block. With pass, you can write the skeleton of your entire program and come back to fill in the details later.
def calculate_tax(income):
pass
def generate_report(data):
pass
def send_email(recipient, message):
pass
class DatabaseManager:
pass
class UserAuthentication:
pass
All of these are valid Python. They can be imported, referenced, and even called. Calling an empty function that only contains pass will simply return None. This makes the pass statement incredibly useful during the early stages of software development when you are thinking about architecture and structure before implementation.
One of the most common uses of the pass statement is inside empty function bodies. When you define a function in Python, the function body must contain at least one statement. If you haven't written the function logic yet, pass serves as the placeholder that keeps your code runnable.
def process_payment(amount, currency):
pass
When you call this function, it runs and returns None without doing anything. This lets you define an interface or API contract before implementing the actual logic — a pattern that is extremely common during development.
Here is a more realistic example showing pass in multiple empty functions that you plan to implement later:
def validate_user_input(data):
pass
def save_to_database(record):
pass
def log_activity(user_id, action):
pass
result = validate_user_input({"name": "Alice", "age": 30})
print(result)
None
The function call succeeds without raising any errors. The program runs to completion and returns None from the empty function. This allows you to test the overall structure of your program before any single function is fully implemented.
The pass statement is equally important when defining empty classes. An empty class body occurs frequently when you want to create a custom exception type, a marker class, or a data structure you plan to fill in later.
Custom exception classes are a perfect example of pass in class bodies:
class DatabaseConnectionError(Exception):
pass
class InvalidUserInputError(Exception):
pass
class PaymentFailedError(Exception):
pass
try:
raise DatabaseConnectionError("Could not connect to the database")
except DatabaseConnectionError as e:
print(f"Caught error: {e}")
Caught error: Could not connect to the database
These custom exception classes are fully functional despite having only pass as their body. They inherit everything from the built-in Exception base class and can be raised, caught, and used exactly like built-in exceptions. This is one of the most practical everyday uses of the Python pass statement.
You can also use pass to create a class that you plan to add methods and attributes to later:
class ShoppingCart:
pass
cart = ShoppingCart()
cart.items = []
cart.items.append("Apple")
cart.items.append("Banana")
print(cart.items)
print(f"Total items: {len(cart.items)}")
['Apple', 'Banana']
Total items: 2
Even with an empty class body, Python still lets you add attributes to instances dynamically. The class is a valid Python object that you can instantiate and work with immediately.
The pass statement is also useful inside conditional blocks when you want to handle a specific condition by doing nothing. This happens more often than you might expect, especially when you want your code to explicitly acknowledge that a condition was considered but requires no action.
def check_age(age):
if age >= 18:
print("Access granted")
else:
pass
check_age(25)
check_age(15)
Access granted
When age is less than 18, the function does nothing — but the pass statement makes the intent clear: this case was considered and deliberately left without action. A reader of the code knows this is intentional, not an accidental omission.
A more practical use case is building out conditional logic incrementally, handling only certain status codes at first:
status_code = 404
if status_code == 200:
print("Request successful")
elif status_code == 201:
print("Resource created")
elif status_code == 404:
pass
elif status_code == 500:
pass
else:
print("Unknown status code")
print("Done processing status code")
Done processing status code
The program runs without errors even though two branches use pass. You can fill in the 404 and 500 handling later while still being able to test the rest of your conditional logic today.
The pass statement can also appear inside loop bodies. This is useful when you need a loop structure that currently does nothing, or when you are building a loop that will be filled in later.
numbers = [1, 2, 3, 4, 5]
for num in numbers:
pass
print("Loop completed")
Loop completed
The loop runs through all five numbers but does nothing with each one. The loop structure is valid and execution continues after the loop finishes.
A more realistic example is when you are building filtering or processing logic to add later:
user_list = ["Alice", "Bob", "Charlie", "Diana"]
active_users = []
for user in user_list:
pass
print(f"Processed {len(user_list)} users")
print(f"Active users collected: {len(active_users)}")
Processed 4 users
Active users collected: 0
You can also use pass in a while loop. The following example shows a basic spin-wait pattern where the loop body intentionally does nothing while waiting for a time condition:
import time
def spin_wait(max_seconds):
start = time.time()
while time.time() - start < max_seconds:
pass
print(f"Finished waiting {max_seconds} second(s)")
spin_wait(1)
Finished waiting 1 second(s)
The pass statement keeps the while loop body syntactically valid while the loop condition handles all the real logic.
Python developers sometimes wonder whether to use pass, a comment, or the ellipsis literal as a placeholder. Each has its place.
A comment (starting with #) is completely ignored by the interpreter and cannot fill an empty block on its own. If you write a function with only a comment inside, Python will raise a SyntaxError because it expects a real statement. The pass keyword is what you need when only a comment appears.
The ellipsis (...) is an actual Python object — the Ellipsis singleton. Like pass, it is a valid statement that does nothing when used on its own line. You will often see ellipsis used as a placeholder in type stub files (.pyi) and in some testing frameworks like mypy. However, it is less conventional than pass for empty function bodies in regular application code.
The Python pass statement is the most conventional and widely understood placeholder. When other developers read your code and see pass, they immediately know: this block is intentionally empty. It is explicit, readable, and semantically clear.
def function_one():
pass
def function_two():
...
print(function_one())
print(function_two())
None
None
Both pass and ellipsis produce None when a function containing only them is called. In regular application code, pass is preferred because it is the most universally recognized placeholder across all Python codebases.
This example brings together all the major uses of the Python pass statement in a single runnable program. It demonstrates pass in custom exception classes, empty class bodies, empty functions, conditional blocks, and loops — showing how it holds together a complete program skeleton during development.
import time
class DatabaseConnectionError(Exception):
pass
class UserNotFoundError(Exception):
pass
class ReportGenerator:
pass
def connect_to_database(host, port):
pass
def fetch_user(user_id):
if user_id <= 0:
raise UserNotFoundError(f"Invalid user_id: {user_id}")
pass
def process_orders(orders):
for order in orders:
if order.get("status") == "pending":
pass
elif order.get("status") == "completed":
print(f"Order {order['id']} is completed")
else:
pass
def run_pipeline():
print("Starting pipeline...")
connect_to_database("localhost", 5432)
print("Database connect step: pass (no action taken)")
try:
result = fetch_user(42)
print(f"fetch_user(42) returned: {result}")
except UserNotFoundError as e:
print(f"Error: {e}")
try:
fetch_user(-1)
except UserNotFoundError as e:
print(f"Caught UserNotFoundError: {e}")
orders = [
{"id": 1, "status": "pending"},
{"id": 2, "status": "completed"},
{"id": 3, "status": "unknown"},
]
process_orders(orders)
generator = ReportGenerator()
print(f"ReportGenerator created: {type(generator).__name__}")
print("Pipeline finished.")
run_pipeline()
Starting pipeline...
Database connect step: pass (no action taken)
fetch_user(42) returned: None
Caught UserNotFoundError: Invalid user_id: -1
Order 2 is completed
ReportGenerator created: ReportGenerator
Pipeline finished.
This complete example shows the Python pass statement serving as a placeholder in custom exception classes (DatabaseConnectionError, UserNotFoundError), an empty class body (ReportGenerator), an empty function body (connect_to_database), a function with partial logic and pass in a branch (fetch_user), and conditional branches inside a loop (process_orders). Every code block is syntactically valid thanks to pass, and the entire pipeline runs from start to finish without errors.