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)