Python Dunder Methods

Ram Vadranam
2 min readMay 21, 2021

Dunder or magic methods in Python are the methods having two prefixes and suffix underscores in the method name. Dunder here means “Double Under (Underscores)”. These are commonly used for operator overloading. Few examples for magic methods are: __init__, __add__, __len__, __repr__ etc.

To understand the use cases creating a class Manager and applying various methods in each use case.

__init__ :

__init__ method instantiate class objects.

Below example, salary is hardcoded at manager class level so that all managers can get the same pay

class Manager:
salary = 60000
def __init__(self, name):
self.name = name
manager1 = Manager('Bob')
print(manager1.name)
print(manager1.salary)
manager2 = Manager('Joe')
print(manager2.name)
print(manager2.salary)

__repr__:

Python __repr__() function returns the object representation in string format. This method is called when repr() function is invoked on the object

class Manager:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"instance of class user:{self.name}"
bob = Manager('Bob')
print(bob)
joe = Manager('Joe')
print(joe)

__call__ :

__call__ method convert class object into a function which can be callable

Expanding the above example to using __call__ method to calculate dynamic pay for managers based on the number of hours worked and wage

class Pay:
total_hrs = 0
total_pay = 0

def __init__(self, wage: int):
self.hourly_wage = wage

def __call__(self, hours_worked):
self.total_hrs += hours_worked
self.total_pay += self.total_hrs * self.hourly_wage
return self.total_pay


class Manger:
pay = Pay(15)

def __init__(self, name: str):
self.name = name

def __repr__(self):
return f"instance of class user:{self.name}"

manager = Manger("BOB")
print(f'Manger {manager.name}, weekly_pay:{manager.pay(40)}')

__get__:

__get__ method converts class object into a variable. This creates a lazy loading pattern for dynamic. Below example working hours added using lazy load patter to Manager class

WORKING_HOURS = {
'001': 3,
'002': 5,
'003': 6
}


class Hours:
def __get__(self, instance, owner):
return WORKING_HOURS[instance.emp_id]


class Pay:
total_hrs = 0
total_pay = 0

def __init__(self, wage: int):
self.hourly_wage = wage

def __call__(self, hours_worked):
self.total_hrs += hours_worked
self.total_pay += self.total_hrs * self.hourly_wage
return self.total_pay


class Manger:
hours_worked = Hours()
pay = Pay(15)

def __init__(self, name: str, emp_id: str):
self.name = name
self.emp_id = emp_id
def __repr__(self):
return f"instance of class user:{self.name}"

manager = Manger("BOB", '001')
print(f'Manger {manager.name}, weekly_pay:{manager.pay(manager.hours_worked)}')
manager = Manger("Joe", '002')
print(f'Manger {manager.name}, weekly_pay:{manager.pay(manager.hours_worked)}')

__add__:

__add__ method allows operations on class object. Below example, Bonus is added to manager class object using __add__ method.

WORKING_HOURS = {
'001': 3,
'002': 5,
'003': 6
}


class Hours:
def __get__(self, instance, owner):
return WORKING_HOURS[instance.emp_id]


class Pay:
total_hrs = 0
total_pay = 0

def __init__(self, wage: int):
self.hourly_wage = wage

def __call__(self, hours_worked):
self.total_hrs += hours_worked
self.total_pay += self.total_hrs * self.hourly_wage
return self.total_pay


class Manger:
hours_worked = Hours()
pay = Pay(15)

def __init__(self, name: str, emp_id: str):
self.name = name
self.emp_id = emp_id

def __add__(self, bonus):
return self.pay + bonus
def __repr__(self):
return f"instance of class user:{self.name}"

manager = Manger("BOB", '001')
print(f'Manger {manager.name}, weekly_pay + bonus:{manager.pay(manager.hours_worked) + 100}')
manager = Manger("Joe", '002')
print(f'Manger {manager.name}, weekly_pay + bonus:{manager.pay(manager.hours_worked) + 50}')

--

--

Ram Vadranam

Blending Technology and Innovation: Navigating the Cloud, Unraveling AI Mysteries, and Empowering Entrepreneurial Journeys