TL;DR
Single and double underscores in Python have different meanings. A single underscore is used to indicate a private variable or method (although this is not enforced), while a double underscore is used to implement name mangling for a variable or method. But most often you’ll see them in dunder methods like __init__.
Explanation
Python is known for its simplicity and readability, underscores play an important role in achieving this. Here are a few example you will most likely encounter:
Leading Single Underscore
_private_var = 9
When a single underscore is used before an object name, it indicates that the object is private and intended for internal use within its class or module. It’s not enforced , but a convention that signals to other developers that the object shouldn’t be used outside of its module or class.
Single underscore
When your function returns multiple objects and you only need 1.
def tuple_returning_function():
return (1,1), (2,2), (3,3)
_ , tuple_I_need, _ = tuple_returning_function()
2. When you’re not using the variables a for loop creates, and you don’t need to store the variable name into anything specific.
for _ in range(0,3):
print("I'm being printed 3 times")
Single trailing underscores: class_
When you want to use a variable name that is already a reserved keyword in python like class, def, type, etc.
To avoid this conflict, you can add a trailing underscore as a naming convention.
type_ = “string”
Dunder methods
Dunder methods are special methods that have names that start and end with two underscores. They are also called magic methods or special methods. These methods are used to define how instances of a class behave in certain situations, like when they are compared to other instances, or when they are added, subtracted, multiplied, or divided.
Here are some common dunder methods in Python:
__init__(self, ...)
: This is the constructor method, which is called when a new instance of a class is created. It initializes the object's attributes.__str__(self)
: This method returns a string representation of the object. It is called when the object is converted to a string using thestr()
function.__repr__(self)
: This method returns a string representation of the object that can be used to recreate the object. It is called when the object is represented using therepr()
function.__add__(self, other)
: This method defines how two objects of the same class are added together. It is called when the+
operator is used.
To make that a bit more clear, here is an example of a class where we define the __add__ dunder method. And add 2 instances of that class with each other:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
print(p3) # Output: (4, 6)
In this example, we have a Point
class that has x
and y
instance variables, and a __add__
method that defines how two Point
objects are added together.
When we add two Point
objects using the +
operator, the __add__
method is called automatically, and it returns a new Point
object whose x
and y
values are the sums of the x
and y
values of the two original Point
objects.
In this example, we create two Point
objects (p1
and p2
), add them together using the +
operator, and store the result in p3
. We then print p3
to verify that it contains the correct values.
The __str__
method is also defined to provide a string representation of the Point
object for printing.
Double Underscore leading an Object name
class MyClass:
def __init__(self):
self.__my_private_variable = 42
def get_my_private_variable(self):
return self.__my_private_variable
In this example, the __my_private_variable
instance variable is marked as "private" by starting its name with a double underscore. This means that it cannot be accessed from outside the class using its original name.
Instead, if you want to access the variable from outside the class, you have to use a mangled name that includes the class name:
my_instance = MyClass()
print(my_instance._MyClass__my_private_variable) # Output: 42
The double underscore prefix causes the variable name to be “mangled” with the class name, effectively making it harder to accidentally overwrite the variable by using the same name in a subclass.
By using a leading double underscore, you can ensure that certain attributes or methods of your class are only accessible from within the class itself. This can help to prevent accidental modification of important internal state, and make your code more robust and maintainable. However, it’s important to note that this does not provide true encapsulation, as the mangled name can still be accessed from outside the class if you know the name.
Conclusion
In conclusion, underscores play a significant role in Python’s simplicity and readability.
“_foo” -> A single underscore indicates a private object that should be used only within the class or module.
“_” Are used to avoid conflicts with reserved keywords
“__foo” Are used for name mangling, making it harder to accidentally overwrite the object by using the same name in a subclass. Preventing accidental modification of important internal state and making code more robust and maintainable.
“__init__” Are Dunder methods, special methods used to define how instances of a class behave in certain situations.