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?

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:

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!


Written on June 11th, 2020