Python: Dunder Methods
Published: 2020-02-10 02:36:27

---
title: Python: Dunder Methods
published: true
description: 
tags: 
---
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:

```python

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:

```python

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:

```python
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.