Python Pass - Doing Nothing, and Why That's Useful
The Python pass
keyword allows you to skip over a block of Python code.
Said differently, it allows you to create a block (whether in a function, loop, or something else) and have that block run with no functionality.
This tutorial will teach you how to use the Python pass
statement. Specifically, we will discuss how the Python pass
statement is useful during the development stage and how it differs from different flow control keywords in Python.
Table of Contents
You can skip to a specific section of this Python pass
statement tutorial using the table of contents below:
- What is the Python
pass
Statement? - How to Use the Python
pass
Statement to Speed Up the Development Stage - The Difference Between
pass
,break
, andcontinue
in Python - How to Use Python
pass
to Explicitly Silence Exceptions - How to Use Python
pass
to Create Type Hierarchies - Final Thoughts
What is the Python pass
Statement?
The Python pass
statement is the statement that we use to create a null operation in Python.
This means that when it is executed, nothing happens! It is a useful placeholder when a statement is required syntactically, but you want no code to be executed.
As an example, here is how you could use a Python pass
statement to create a function that performs nothing when invoked:
def my_func (arg):
pass # A function that does nothing (yet)
Similarly, here is how you could use the Python pass
statement to create a Python class with no methods or properties:
class my_class:
pass # A class with no methods or properties (yet)
This might seem completely useless at first.
However, the Python pass
statement is actually extremely valuable.
We will explore various use cases for the Python pass
statement throughout the rest of this tutorial.
How to Use the Python pass
Statement to Speed Up the Development Stage
The development stage of building a project is probably the most useful place to use the Python pass
statement. Let's explore how and why to use the Python pass
statement during the development stage.
During development, we sometimes want to ignore the explicit behaviour of a code block in order to continue building the main flow of our program with the intention of adding the functionality in that code block later.
For example, let's build a program that takes in a message from the user, replaces all the spaces in that message with underscores, and then prints it out to the user.
We might start this program like so:
if __name__ == "__main__":
in = input("Please enter your message: ")
## Convert all spaces to underscores
result = in.replace(' ', '_')
print(f"Here is your resultant: {result}")
However, what if you needed to validate the user input before performing the manipulations and then write the resulting message to a file?
When adding a new feature to existing code developers like to use stubs to add space for future functionality in existing code.
Here's an example:
def validate_input(msg):
if (len(msg) > 0):
return True
else:
return False
# TODO
def write_to_file(msg):
pass
if __name__ == "__main__":
in = '' # empty string
# Validate, looping until valid message received
while (validate_input(in) is not True):
in = input("Please enter your message: ")
## Convert all spaces to underscores
result = in.replace(' ', '_')
print(f"Here is your resultant: {result}")
write_to_file(result) # Call our stub
In this example, we used the Python pass
statement to create a stub for the write_to_file
function.
We have not written the function yet, but the stub reminds us that it is still necessary to do later (hence the TODO
comment). This saves us time now while preventing us from forgetting to finish the function later.
We will need to eventually implement the function. In the meanwhile, the Python pass
statement allows the developer to confirm that the rest of the program is functioning correctly before completing the write_to_file
function.
This helps speed up development because at this point if we were to find a bug, the scope of that bug is smaller. This means that the bug will be easier to find.
Keep in mind that write_to_file
is a very simple use case. You could probably implement this function in a few minutes. Because of this, you would not need to stub it out at all.
However, this concept applies to much more complicated functions. An example is encryption algorithms, which need to be thoroughly tested in isolation before being applied to a login system.
Now let's go through a slightly different use case that still relates to speeding up our development cycle.
When using conditional statements within a loop to decide how the data should flow through your program, you sometimes need to simply do nothing when a certain criterion is satisfied.
For example, consider the example of counting the number of odd and even numbers in a sequence while ignoring all 0's.
def count_numbers(sequence):
evens = 0
odds = 0
for (num in sequence):
# Even numbers should be divided by 2
if num % 2 == 0:
evens = evens + 1
# Odd numbers will not divide by 2 evenly
elif num %2 != 0:
odds = odds + 1
# Otherwise, zeroes should be ignored
else:
pass
In this case, you need to account for the current number in the sequence being a 0, but you really don't need to do anything with that information.
You could easily rearrange this solution and check for if the number was a 0 and step to the next loop iteration, or add an extra check for the 0's and count them, then simply not return the data.
However, in this case, it's much simpler and less time consuming to just do nothing with pass
!
The Difference Between pass
, break
, and continue
in Python
A common question about the Python pass statement asked is the difference between pass
, break
, and continue
.
The differences between these three statement can most easily be understood by look at an example:
if __name__ == "__main__":
print("break:")
for val in "Python":
if val == "h":
break
print(val)
print("----")
print("continue:")
for val in "Python":
if val == "h":
continue
print(val)
print("----")
print("pass")
for val in "Python":
if val == "h":
pass
print(val)
print("The End")
Output:
break:
P
y
t
----
continue:
P
y
t
o
n
----
pass
P
y
t
h
o
n
The End
break
will end the loop while continue
and pass
both allow the loop to complete.
However, the subtle difference between continue
and pass
is that the continue
statement will restart the loop on its next iteration.
When the condition (val == "h"
) was met and continue
was called, val
was increment and the loop continued.
When the condition (val == "h"
) was met and pass
was called, nothing happened at all and the loop continued.
How to Use Python pass
to Explicitly Silence Exceptions
There are certain cases where you may want to simply ignore an exception from being raised by your Python script. This can be helpful when the exception is irrelevant to the performance of your script.
This may sound like a bad coding practice, and it very well can be if used improperly!
Here is an example of the correct way to use this trick, taken from the xml
library for Python:
try:
self.version = "Expat %d.%d.%d" % expat.version_info
except AttributeError:
pass # unknown
The AttributeError
is probably the most commonly used error in the xml
library.
In this case, usually we want to ignore this error for various reasons.
The main time to use this technique is when logging optional object attributes from an instance during runtime.
In this case, the version
attribute is not an option for the class, and therefore the line of code self.version = "Expat %d.%d.%d" % expat.version_info
will raise an AttributeError
. Since the developer was only using this value for logging, they don't need to escalate this exception at all.
An example of what NOT TO DO would be this:
try:
os.unlink(some_filename)
except:
pass
Can you guess why this is a horrible practice?
It's because here we would be ignoring ALL types of errors raised within the try
block. This means that any error that occurs, whether it be an AttributeError
or FileNotFoundError
, is simply ignored.
This is dangerous because you could potentially be ignoring a fatal error in your code. As a general rule of thumb, if you plan to use the pass
statement to silence an exception, make sure you are deliberately silencing just the one!
How to Use Python pass
to Create Type Hierarchies
Type hierarchies are used to create a family of parent-child relationships between classes.
In this case, we would be able to inherit functionality from a parent class into a child class in order to extend or override the behaviour.
The most prevalent example of creating type hierarchies in Python would be Exceptions
. Fundamentally, all Exception classes work the same way. However, it's beneficial to create a subclass with a much more specific exception name in order to more accurately represent the errors happening in your code.
An example of this would be the ImportError
which is a parent class to children such as the ModuleNotFoundError
. The ImportError
is raised when an import
statement has trouble successfully importing the specified module. This can be more accurately represented by the ModuleNotFoundError
.
In this case, the code behind the ImportError
and the ModuleNotFoundError
is identical. When the exceptions are raised to a developer the name ModuleNotFound
gives a much more accurate indication of what the problem is. This most likely indicates an issue with the path to the module you're trying to import.
So, in this case, we have a type hierarchy that looks like this:
Now, how does this pertain to a pass
statement?
As I mentioned, the behaviour of the ModuleNotFoundError
would be the same as it's parent class ImportError
. The code would look like this:
class ModuleNotFoundError(ImportError):
pass
This is a very simple use of the Python pass
statement which allows you to create a subclass that does not change the behaviour of the parent. Instead, it allows you to create a more accurate name of that class.
Let's put this example in a more user-friendly context.
Imagine we had a program where you needed to read a file from a server. The FileNotFoundError
may be a very useful exception to detect problems within your code.
However, let's assume that when you attempt to read assets from your server there are multiple different file types (images and text files). In this case, to be more specific in your code and to help developers understand the exception, you can create a type hierarchy like so:
# Subclass of FileNotFoundError for images
class ImageNotFoundError(FileNotFoundError):
pass
# Subclass of FileNotFoundError for text files
class TextFileNotFoundError(FileNotFoundError):
pass
We now have this type hierarchy:
-
-
-
-
ImageNotFoundError
TextFileNotFoundError
-
-
-
Here, ImageNotFoundError
and TextFileNotFoundError
are called siblings because they are both children of the same parent. You can think of it as a tree and both these errors are living at the same level. This makes them siblings.
This sort of functionality can be extended even further to add more accurate information to your exceptions:
# Subclass of ImageNotFoundError for jpeg's
class JpegNotFoundError(ImageNotFoundError):
pass
# Subclass of ImageNotFoundError for png's
class PngNotFoundError(ImageNotFoundError):
pass
Now that we've created more accurately named errors for our program to raise, let's see what they would look like to a developer.
We can write a simple script to raise our exception:
if __name__ == "__main__":
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 'foobar')
Which will give this output:
Traceback (most recent call last):
File "pass.py", line 7, in <module>
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 'foobar')
FileNotFoundError: [Errno 2] No such file or directory: 'foobar'
When raising one of our children classes, JpegNotFoundError
for example, we can see the difference is minimal but provides a lot more information to a developer.
if __name__ == "__main__":
raise JpegNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 'foobar')
Which will give this output:
Traceback (most recent call last):
File "pass.py", line 7, in <module>
raise JpegNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 'foobar')
JpegNotFoundError: [Errno 2] No such file or directory: 'foobar'
Final Thoughts
This tutorial explained what the Python pass
statement is, how it is useful, and when you should be using it.
Learning how to use Python pass
properly will benefit you primarily by speeding up your development stage. Said differently, the Python pass
statement can make you a more efficient developer!
With that said, it's important to understand the proper usage of the Python pass
statement in order to avoid bad coding practices and introducing bugs in your code.
Remember, if you are using pass
to silence an exception, be very specific and never silence all errors!