The pass statement is one of the smallest keywords in Python, but it solves a real problem: Python requires every code block to contain at least one statement, and pass is how you satisfy that rule when you have nothing to say yet.
Every language that uses indented blocks needs a way to represent intentional emptiness. In Python, that mechanism is a single keyword: pass. When the interpreter encounters it, nothing happens — no value is returned, no variable is changed, no side effect is produced. Execution simply continues to the next line. That may sound trivial, but it turns out to be exactly what you need in several common situations.
What is pass and why does Python need it?
Python uses indentation to define code blocks. After a colon at the end of a def, class, if, for, while, with, or except line, Python expects at least one indented statement to follow. If the block is completely empty, the parser raises a SyntaxError.
# This raises SyntaxError: expected an indented block
def process_data():
# TODO: implement later
A comment alone is not enough — the parser strips comments before it even evaluates the block. The only thing that will satisfy the requirement is a real statement. pass is that statement.
# This is valid Python — pass fills the required slot
def process_data():
pass # TODO: implement later
The technical term for what pass does is a null operation (NOP). At the bytecode level, it compiles to a single NOP instruction that the interpreter executes and immediately discards. It has no measurable performance cost.
Build a valid empty function stub named send_report that uses pass:
def, then the function name send_report, then parentheses (), then a colon :. After the colon, Python requires at least one indented statement — that is pass. Using return here would also be valid syntax, but pass is the conventional placeholder when you intend to add real logic later. The pipe token | does not belong here.
Five places where pass is useful
There are five contexts where pass appears regularly in Python code. Three involve scaffolding during development. Two involve permanent use in production.
1. Empty function stubs
When designing a module, you often want to define all the function signatures first and fill in the logic later. pass lets you establish the full API before writing a single line of implementation.
def load_user(user_id):
pass # TODO: query database
def save_user(user):
pass # TODO: write to database
def delete_user(user_id):
pass # TODO: remove from database
2. Empty class definitions
A class with only a pass body is valid Python. This pattern is common for two purposes: creating a named placeholder type during early development, and defining a custom exception class that inherits all behavior from its parent without adding anything new.
# Stub class — fill in attributes and methods later
class ReportConfig:
pass
# Custom exception — permanent, intentional use of pass
class AuthenticationError(Exception):
pass
Minimal custom exceptions are one of the cleanest permanent uses of pass. Writing class DatabaseConnectionError(Exception): pass gives you a distinct, catchable exception type without any extra implementation. Callers can catch it by name rather than by the generic Exception class.
3. Conditional branches you are not handling yet
When sketching out multi-branch logic, you may know all the conditions but not yet know what each branch should do. pass lets you write the full structure without committing to the content.
status = "pending"
if status == "approved":
pass # TODO: trigger fulfillment workflow
elif status == "rejected":
pass # TODO: send rejection notification
elif status == "pending":
pass # TODO: send reminder email
else:
pass # TODO: log unknown status
4. Loop bodies that intentionally do nothing
pass inside a loop is less common, but it appears when you need to advance a loop without performing any action on certain iterations. Note the important distinction: pass does not skip the rest of the iteration — it simply does nothing and falls through to the next statement inside the loop block.
events = ["login", "logout", "login", "purchase", "login"]
for event in events:
if event == "login":
pass # login events handled elsewhere
else:
print(f"Processing: {event}")
5. Silent exception handling
Placing pass in an except block silently swallows an exception. This is valid Python, but it is also a pattern to use deliberately and sparingly. Silent failures are hard to debug. When you do use it, add a comment explaining why the exception is being ignored.
try:
config = load_optional_config()
except FileNotFoundError:
pass # config file is optional; defaults will be used
Catching a broad exception like Exception or BaseException with pass is almost always a mistake. It can hide real errors, including typos, network failures, and logic bugs. Keep your except clauses as specific as possible.
The function below contains one bug. Click the line you think is wrong, then hit check.
pass. A comment alone does not satisfy Python's requirement that a code block contain at least one real statement. The if amount > 0: block would raise a SyntaxError at runtime because the block is empty. Writing pass # handle positive balance makes the block valid while preserving the intent.
pass vs. continue vs. return
New Python learners often mix up three keywords that all relate to "not doing something." The distinction matters, and the accordion below summarizes each one so you can compare them at a glance.
- Effect
- Does nothing. Execution continues to the next statement normally.
- Valid in
- Any block: functions, classes, loops, conditionals, except clauses.
- Effect
- Skips the remainder of the current loop iteration and jumps immediately to the next one.
- Valid in
- Only inside
fororwhileloops.
- Effect
- Exits the function immediately and optionally sends a value back to the caller.
- Valid in
- Only inside function definitions.
# pass — does nothing, loop continues normally
for i in range(5):
if i == 2:
pass # no effect; print still runs
print(i) # output: 0 1 2 3 4
# continue — skips the rest of the iteration
for i in range(5):
if i == 2:
continue # jumps to next iteration
print(i) # output: 0 1 3 4
# return — exits the function
def first_even(numbers):
for n in numbers:
if n % 2 == 0:
return n # exits here
return None
How to Use pass in Python
-
1
Recognize where a statement is required
Identify the code block that Python requires to contain at least one statement. This includes function bodies, class bodies, loop bodies, conditional branches, and
exceptclauses. If the block is intentionally empty right now, it needspass. -
2
Write pass on its own indented line
Inside the block, type
passon a single line, indented to the correct level. No parentheses, no arguments. The wordpassby itself is the entire statement.pythonclass UserSession: pass -
3
Add a comment to signal intent
Follow
passwith a short inline comment so that anyone reading the code — including yourself in three months — understands that the block is not accidentally empty. Common conventions are# TODO: implement,# intentionally empty, or a brief description of the planned logic.pythondef validate_token(token): pass # TODO: add JWT validation logic -
4
Replace pass with real logic when ready
Once you implement the functionality, delete the
passline and put the real code in its place. Python does not needpassonce the block has at least one other statement. The exception is permanent uses — minimal exception classes, intentionally silentexcepthandlers — wherepassis the intended permanent content.
Python Learning Summary Points
passis a null operation — it does nothing when executed and has no effect on program state or control flow.- Its primary purpose is to satisfy Python's requirement that every code block contain at least one statement, allowing you to define empty stubs for functions, classes, loops, and conditionals.
passdiffers fromcontinue(which skips the current loop iteration) andreturn(which exits the function). Understanding these three keywords is essential for writing clear Python control flow.- In production code, the two cleanest permanent uses of
passare minimal custom exception classes and intentionally silentexcepthandlers where the omission is deliberate and documented. - Always pair a scaffolding
passwith an inline comment explaining the intent. Remove thepassonce you replace it with real logic.
Learning pass is a small step, but the habit it teaches — defining structure before filling in details — is how larger Python programs get built. Sketch the skeleton, validate the logic, then implement. pass is what makes that workflow syntactically legal.
Frequently Asked Questions
pass is a null operation — it does absolutely nothing when Python executes it. It satisfies the syntactic requirement that a code block must contain at least one statement, without performing any action.
pass does nothing and execution continues to the next line normally. continue skips the rest of the current loop iteration and jumps back to the loop header to begin the next iteration. They behave identically only when pass is the very last statement in a loop body — in every other position, the difference is observable.
pass is a no-op placeholder that does not exit the function. Execution falls through to whatever comes next. return explicitly ends the function and optionally sends a value back to the caller. Using return in an empty stub is valid but signals that the function is complete, which a scaffolding stub is not.
Use pass in a class body when you want to define the class name now and add attributes or methods later. It is also the standard pattern for defining minimal custom exception classes that inherit all behavior from a parent class without adding anything new — for example, class ValidationError(ValueError): pass.
No. A comment is stripped by the parser before the interpreter ever sees it. pass is a real statement that the interpreter processes — it just produces no effect. An empty block that contains only a comment is a SyntaxError; the same block with pass is valid.
Yes. Placing pass in an except block silently swallows the exception. This is valid Python syntax, but it should be used deliberately. Silencing exceptions without logging or handling them can hide bugs. Always keep the except clause as specific as possible and include an inline comment explaining why the exception is being ignored.
No. pass compiles to a single NOP bytecode instruction and has no measurable runtime cost. You do not need to remove it for performance reasons — only for clarity once real logic is in place.
Only when it serves a permanent purpose — a minimal exception class, an intentionally empty callback, or a documented silent handler. Scaffolding uses of pass should be replaced with real logic before shipping. A pass left in production code without a clear explanatory comment is a signal that something was not finished.