Let's talk about how third-party library authors use dunder methods to make their Python objects feel like native Python objects.
Let's add two variables,
>>> x = 2 >>> y = 3 >>> x + y 5
When Python executed this code, it called the
__add__ method on
x, passing it
>>> x.__add__(y) 5
__add__ is pronounced "dunder add", dunder as in double underscore because it starts and ends with two underscores.
If we look for help on
x (which points to an integer) we'll see there are lots of dunder methods (all those methods named
>>> help(x) Help on int object: class int(object) | ... | | Methods defined here: | | __abs__(self, /) | abs(self) | | __add__(self, value, /) | Return self+value. | | __and__(self, value, /) | Return self&value. | | __bool__(self, /) | self != 0 | | ...
A dunder method acts as a contract between the Python interpreter and the person who made a particular Python class.
The person who made the
int class defined the
__add__ method to let Python know that the
+ symbol works on
Addition relies on a dunder method, but so do many other operations.
In fact, when you try to ask if two things are equal, that uses the
Even equality relies on dunder methods in Python!
Dunder methods are a contract between the person who made the class, and Python itself.
As Python programmers, we're not supposed to call dunder methods directly.
Instead, we're meant to use the high-level operations (like the
== operators) that rely on those dunder methods.
Let's see an example of why we're not supposed to call dunder methods directly.
If we check for equality between an integer and a floating point number by manually calling
__eq__, we'll see
>>> y = 3 >>> z = 3.0 >>> y.__eq__(z) NotImplemented
NotImplemented is a special value that tells Python, as an integer, I don't know how to check myself for equality with a floating-point number.
So Python then has to ask
z, the floating-point number, "are you equal to the
y, the integer?":
>>> z.__eq__(y) True
That's the reason
y == z actually works:
>>> y == z True
We're supposed to do things (like equality check here), using the
== operator. We're not supposed to use the dunder methods directly.
It's Python's job is to call the dunder methods; our job is to do the high-level operation instead.
Dunder methods in Python power operators like
They also power some of the built-in functions.
For example, if you ask for the length of something:
>>> name = "Trey" >>> len(name) 4
That relies on the
>>> name.__len__() 4
len function is a built-in function (as opposed to a method) because Python has decided that having a length is a pretty fundamental property of an object.
So Python has a built-in function called
len that delegates to a dunder method which is used for discovering whether something has length and what that length is.
Having a length is all about having a
>>> numbers = [2, 1, 3, 4, 7] >>> numbers.__len__() 5 >>> len(numbers) 5
In fact, many of the things that seem, completely fundamental to Python, like indexing a list, are powered by dunder methods.
>>> numbers 2
Whenever you use square brackets on an object in Python, the
__getitem__ method is called:
>>> numbers.__getitem__(0) 2
So dunder methods, power pretty much all the operators in Python and even some of the built-in functions.
A dunder method is a method (that Python knows about), which has two underscores before it and two underscores after it.
It's a contract between the person who implemented a certain class and the Python interpreter, which knows when to call that particular dunder method.
If you make your own classes in Python, you can use dunder methods for operator overloading. And that's actually what third party library authors do, in order to make the objects in their libraries act like native Python objects.
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.