Have you ever seen a variable in Python that has two underscores on either side of it (__like_this__
)?
These are officially referred to as special attributes or special methods, but many Python programmers refer to them as dunder variables or dunder methods.
That word dunder stands for "double underscore" because these variables are always surrounded by two underscores (__dunder__
).
Dunder variables define a contract between Python programmers and the Python interpreter.
Python uses dunder variables for two general purposes:
That's extremely hand-wavy. What does "convey information" really mean?
Let's look at some examples.
Python stores docstrings in a __doc__
attribute:
>>> import math
>>> math.__doc__
'This module provides access to the mathematical functions\ndefined by the C standard.'
>>> math.sqrt.__doc__
'Return the square root of x.'
And Python stores the names of classes in a __name__
attribute:
>>> def what(thing):
... print("That's a", type(thing).__name__)
...
>>> what("[1, 2]")
That's a str
>>> what([1, 2])
That's a list
In fact, modules and functions have a __name__
attribute too.
You'll sometimes see a __name__
check at the bottom of a Python script to ask the question "is this module the entry point to our Python process"?
Python uses many dunder variables to convey information about objects to us (and to convey information back to itself).
Below are a few common dunder variables you might want to access yourself.
Classes use these dunder attributes:
__name__
: stores their name__dict__
: stores their attributes (see where attributes are stored)__module__
: stores the name of the module they were defined in within__bases__
: stores their base classes (see inheritance)__mro__
: stores their method resolution orderFunctions use these dunder attributes:
__name__
: stores their name__dict__
: stores their attributes__module__
: stores the name of the module they were defined in within__defaults__
and __kwdefaults__
: store their default argument valuesModules use these dunder attributes:
__name__
: stores their name__dict__
: stores their attributes__file__
: the file this module was loaded from (though some modules are missing this)All objects use these dunder attributes:
__class__
: stores the class of the object attribute__dict__
: stores their attributes (well, usually)As Python programmers, we can also use dunder variables to convey information to Python.
This is usually done with dunder methods when making a class.
The most common dunder methods to customize are:
__init__
: defines an initializer method__repr__
: defines a custom string representation__eq__
: defines how equality worksDunder methods are for us to define, but not for us to call.
If we want to see the programmer-readable string representation of an object, we could use the built-in repr
function:
>>> n = 2
>>> repr(n)
'2'
Python uses the __repr__
under the hood for this.
>>> n = 2
>>> n.__repr__()
'2'
But we shouldn't call __repr__
ourselves: that's Python's job, not ours.
There are other cases where dunder variables are used for conveying information to Python, but they're far less common than dunder methods.
One example is the module-level __getattr__
method.
Another is the class-level __slots__
attribute.
Dunder variables, attributes, and methods have two purposes:
Dunder methods are typically for us to convey information to Python. Other dunder variables are sometimes for Python to convey information to us.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.