DEV Community

Zander Bailey
Zander Bailey

Posted on

Python: Dunder Methods

Python classes are not as vital as they are in a language like Java, but they are still important, and it can be very handy to have an understanding of the inner workings of classes and what makes them tick. An important part of this is Special Methods, more commonly known as ‘Dunder’ methods. The term ‘Dunder’ comes from ‘Double Underscore’, because they use the naming convention of being enclosed in double underscores, like __init__. These are all methods that are run when certain conditions occur, and are not called manually by the program. A few basics to start with are __init__ and __new__. These two are very similar in that they both occur upon instantiation of an instance of the class. But __init__ occurs just after creation, and __new__ occurs just before. To explain, __init__ is called after the object is created and give special instructions for setting it up before returning the instance. __new__ happens before the object is created, and allows customization of the instance creation. To give an example, let’s say we’re making a class to hold grid coordinates, and we want assign the coordinates upon creation:


Class Coords():

    def __init__(self, x,y):
        self.x = x
        self.y = y

This tells the class that a new instance can accept x and y coordinates as parameters, and it will immediately assign those to it’s own personal x and y variables. Now __new__ allows us to perform some operations just before the object is created, so now let’s say that only want to make coordinates with positive y values:


Class Coords():

    def __new__(cis,x,y):
        if y >= 0:
            return object.__new__(cls)
        else:
            return none

    def __init__(self, x,y):
        self.x = x
        self.y = y

So now we can make sure to perform certain operations every time an instance is created, but before instantiation. __repr__ and __str__ are two more dunder methods that also have uses, where both are used for turning the object into a string but in different situations. __repr__ is typically used for debugging, and is the ‘official’ string representation of the object, often an ‘expression’ that could be used to create the object. So {'a':1,'b':2,'c':3} becomes "{'a': 1, 'b': 2, 'c': 3}”. __str__ on the other hand, is the string representation of the object when cast with str() or the default for print().

One last category to talk about is what are known as ‘rich comparison’ methods. These are methods that represent the functionality for mathematical operators, like + or -. For these it’s easier to just the methods and what operators they correspond to:

Class Coords():

    def __init__(self, x,y):
        self.x = x
        self.y = y

    def __lt__(self, other):
        #Less Than: <
        return self.x < other

    def __le__(self, other):
        #Less Than or Equal To: <=
        return self.x <= other

    def __eq__(self, other):
        #Equals: ==
        return self.x == other

    def __ne__(self, other):
        #Not Equal: !=
        return self.x != other

    def __gt__(self, other):
        #Greater Than: >
        return self.x > other

    def __ge__(self, other):
        #Greater Than or Equal To: >=
        return self.x >= other  

These allow you to customize how comparisons work for objects that don’t have an obvious method of comparing. There are many other ‘Special Methods’, and they can allow you do do many interesting and useful things when creating your own classes, and I have tried to give you an idea of how they work, and how they can be useful.

Top comments (0)