Python can sometimes look weird for starters, mostly when they have a background in another programming language. A common example is the underscore, which is used by python internally or in some well-established conventions across developers. Some of them are documented, but others you may come occasionally across the longer you write and maintain python code.
Conventions
There are two widespread conventions in python that imply the underscore. They are related to naming variables and methods. A leading underscore means that something was defined that is meant to be used only internally in a module.
class Example(Parent):
_my_prop = 1234
Depending on your IDE or editor, you might get a warning when trying to access _my_prop on an instance of the class Example. Of course this is still valid Python code, but the convention is well known and this is why the IDE shows the warning.
In some cases you want to use a specific name for a method or property on a class, but the name might be already reserved by python and you will overwrite its behavior. In such a case you may better think of another name, but by convention developers decide to add a trailing underscore if there isn’t really a better name for what they need.
class Example(Parent):
def my_func_():
pass
To be fair, I’m not a big fan of this and I never really had to use it. But in case you find it in the python code of somebody else, you know at least what the intention of the developer was.
Also, a known convention is to use the underscore for internationalization and localization.
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
Dunders
When using double underscores (or short dunders) you will get some interesting behavior Python. First of all there are the special methods in python that have reserved name that use a double leading and double trailing underscore.
class Example(Parent):
def __init__(self, *args, **kwargs):
pass
In case, you are not familiar, I would recommend going throw the documentation of the Python data model. It will help understand more of what python does with objects under the hood.
If you need a property or method that should be used only on the instance of your model, but you don’t want it to be accessible when another objects is inheriting you base model you can then use a double leading underscore.
class Example(Parent):
def __my_func(self, *args, **kwargs):
pass
This will actually not exclude the value on the child instance, but it will mangle the name, so it will include the class name in it.
class A(object):
__prop_private = “hallo”
prop_public = “world”
class B(A):
pass
a = A()
b = B()
# regular
print(a. prop_public)
print(b. prop_public)
# mangeled
print(a. _A__prop_private)
print(b. _A__prop_private)
Single underscore
The single underscore has also a special meaning in python, and you should avoid it inside your python code (except if you use it for translations). Where you should consider using it is in the REPL, as it makes sense in this condext. The underscore is actually returning the last value that was printed by python. This means you can access some computation after execution and later store it into a variable and use it for something else: