Python - How to Use Underscores in Your Code

Published on Dec. 21, 2017, 7:35 a.m.

Note: This post was derived from Dan Bader's post on underscores that explains the subject in a lot more detail. If you are interested in reading his article, go here.

If you're a new Python programmer, you are likely encouraged to have a look at other programmer's code. Python code has a particular look to it. Some of the code that may stand out to you is the use of underscores: _. There are times when using an underscore makes sense and times when it tells the interpreter to do something special. Below are five situations where you will likely see underscores and the reasons/meanings behind them.

The Single Leading Underscore

Example: _my_var

This one is a Pep8 convention but not enforced by the Python interpreter. Use this when you want to make a class method private. Since private class methods and variables are not enforced by the interpreter, this is merely a pattern that tells the consumer of your class to consider not using it in derivative code.

The Single Trailing Underscore

Example: class_, for_

Single trailing underscores are not enforced either by the Python interpreter. However the convention of use for these is when it makes sense to use a Python keyword as a variable.

For example, let's say you have a function definition that takes an arbitrary class as a parameter you can do this:

def my_func(self, class_):

The Double Leading Underscore

Example: __my_var

The double leading underscore is a bit tricky. I used to believe this was how you actually made and enforced a private variable or method. But, the Python interpreter treats this double underscore by internally giving it another name. For example:

We create a class called MyClass:

>>> class MyClass(object):
...     foo = 'Foo'
...     _bar = 'Bar'
...     __baz = 'Baz'

And then show its attributes:

>>> dir(MyClass)
['_MyClass__baz', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']

Note that there while there are _bar and foo attributes, there is no __baz attribute. Oh wait, yes there is but see that it's been changed to 'MyClass_baz'!

So, what if we create another class that inherits MyClass?

>>> dir(MyDerivedClass)
['_MyClass__baz', '_MyDerivedClass__baz', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']

Note that our new __baz does not overwrite the derived MyClass's __baz. Each class has its own __baz with a prepended class name. The double prepended underscores simply tells the interpreters to keep the original method or variable as is and does not allow for an overridden one.

The Double Leading and Trailing Underscore

Example: __init__, __name__, __my_var__

These generally give you a hint that variables like init and name are being used by Python and you should avoid the surrounding double underscores to be on the safe side. That's really all there is to these.

Literal Single Underscore

Example: _

The literal single underscore is simply a throwaway variable. You could use it if needed but it generally signals that the variable is being minimally used (in a for loop for example) but likely won't be used later.

Here's a good example. Let's say we want to create a function that will print out 'Hello' a hundred times. We can use it for this:

for _ in range(0, 100):

This is similar to the $_ variable in Perl (called the default variable) that can be used on a temporary basis.

Hopefully this clears up any misunderstandings of the use of underscores in Python. I would encourage you to experiment with them in different situations so that your understanding of them increases.

If this blog is helpful, please consider helping me pay it backward with a coffee.

Buy Me a Coffee at