Python Dunder Methods

Hasan Özdemir
5 min readJan 24, 2023

--

Python “dunder” (short for “double underscore”) methods, also known as magic methods, are special methods that have double underscores at the beginning and end of their names, such as init or add. These methods allow you to define how your objects should behave in certain situations, such as when they are added together or when they are used in a for loop. ca

Here are some examples of dunder methods and how to use them:

__init__

This method is used to initialize an object when it is created. It is called automatically when the object is created, and any arguments passed to the object’s constructor are passed to this method.

__str__

This method is used to define how the object should be represented as a string. It is called when the built-in str() function is used on the object, or when the object is used in a string context (such as being printed).

__add__

This method is used to define how the object should behave when it is added to another object. It is called when the + operator is used on the object.

__iter__

This method is used to define how the object should behave when it is used in a for loop. It should return an iterator object.

__delitem__

This dunder method is used to define behavior for the del statement when used on an object that is an instance of a class.

__setitem__

This dunder method is used to define behavior for the assignment operator (=) when used on an object that is an instance of a class.

__getitem__

This dunder method is used to define behavior for when an object that is an instance of a class is accessed like a list or a dictionary.

__len__

This dunder method is used to define behavior for the built-in len() function when used on an object that is an instance of a class.

__contains__

This dunder method is used to define behavior for the in keyword when used on an object that is an instance of a class

These are just a most used examples of dunder methods, there are many others. It’s useful to know about these methods because they allow you to define how your objects should behave in certain situations, allowing you to create more expressive and user-friendly code.

Pros and Cons of Dunder Methods

Pros of using dunder methods:

  1. They allow you to define how your objects should behave in certain situations, such as when they are added together or when they are used in a for loop. This can make your code more expressive and user-friendly.
  2. They give you more control over the behavior of your objects, making it easy to define custom behaviors for common operations.
  3. They allow you to overload operators, such as + and <, so that you can use them with your own custom classes.
  4. They make it easy to implement common design patterns, such as the iterator pattern, by providing dunder methods such as iter.

Cons of using dunder methods:

  1. They can make your code more complex, especially if you use a lot of them or use them in complex ways.
  2. They are not always obvious to understand, especially for people who are not familiar with Python.
  3. They can make it harder to debug your code, since the behavior of your objects is not always immediately obvious.
  4. They can make it harder to test your code, since you need to test the behavior of your objects in various situations.

It’s important to note that dunder methods are not always necessary in every project, it depends on the complexity of the project and the goals of the project. It’s important to weigh the pros and cons of using dunder methods in your project, and decide whether they are the right tool for the job.

Example Project : Library Management System

The system allows you to create, read, update, and delete books, as well as search for books by title and author. It also has advanced features such as sorting the books by title or author, and comparing books to see which one has a more recent publication date:

import re

class Library:
def __init__(self):
self.books = {}

def __setitem__(self, ISBN, book):
self.books[ISBN] = book

def __getitem__(self, ISBN):
if ISBN not in self.books:
raise ValueError(f"Book with ISBN {ISBN} not found.")
return self.books[ISBN]

def __delitem__(self, ISBN):
if ISBN not in self.books:
raise ValueError(f"Book with ISBN {ISBN} not found.")
del self.books[ISBN]

def __len__(self):
return len(self.books)

def __contains__(self, ISBN):
return ISBN in self.books

def _validate_ISBN(self, ISBN):
if not re.match(r'^\d{13}$', ISBN):
raise ValueError(f"Invalid ISBN: {ISBN}")

def add_book(self, ISBN, title, author, year):
self._validate_ISBN(ISBN)
if ISBN in self.books:
raise ValueError(f"Book with ISBN {ISBN} already exists.")
self.books[ISBN] = {'title': title, 'author': author, 'year': year}

def update_book(self, ISBN, title=None, author=None, year=None):
if ISBN not in self.books:
raise ValueError(f"Book with ISBN {ISBN} not found.")
if title:
self.books[ISBN]['title'] = title
if author:
self.books[ISBN]['author'] = author
if year:
self.books[ISBN]['year'] = year

def delete_book(self, ISBN):
if ISBN not in self.books:
raise ValueError(f"Book with ISBN {ISBN} not found.")
del self.books[ISBN]

def search_book(self, ISBN):
if ISBN not in self.books:
raise ValueError(f"Book with ISBN {ISBN} not found.")
return self.books[ISBN]

--

--