Python Double Underscore (Dunder)

In Python, you can enrich your classes with dunder methods. These are considered magic or special methods. Although, they aren’t as unique as you may think.

They are easy to spot because they start and end with double underscores, hence where the ‘dunder’ name comes from. For example, __init__ or __name__. You can treat them like regular functions in normal python.

Dunder methods let you add extra properties to your classes. For example, len() in python will return the length of something to you, however, this functionality isn’t supported out of the box with classes.

But if you add a __len__ dunder to your class, then you’ll be able to use len(your_class).

class Student:
    def __init__(self):
        self.num_tests = 10  	
  
    def __len__(self):
        return self.num_tests

bob = Student()
len(bob)
>>> 10

The list of common dunders within classes include:

  • __init__: This constructor takes care of the basics. It helps set up the object
  • __str__: The ‘nice’ version of the printed object. This is a human readable format to print
  • __repr__: The ‘official’ string of the object. This is what will print when you return the object
  • __len__: The method that runs when you call len() on your object
  • __getitem__: You’ll be able to return a specific item (if you have a list of them) within your object
  • __getattr__: A ‘catcher’. If you try calling an attr that doesn’t exist, this function will return a value you set. If it does exist, it will do nothing.
  • __reversed__: Only applicable if you have __len__ and __getitem__. This will return the reverse of items that you set

Let’s take a look at a python dunder code sample


Python Dunder

In python, dunders are magic or special functions that aren't really magic or special at all. They help give more functionality to your classes.

Let's look at a few examples

In [59]:
class Student():
    def __init__(self, name):
        self.name = name
        self.tests = []
        
    def __repr__(self):
        return 'Student ({})'.format(self.name)

    def __str__(self):
        return 'Student with name of {}'.format(
            self.name)
    
    def __len__(self):
        return len(self.tests)
        
    def __getitem__(self, pos):
        return self.tests[pos]
        
    def __getattr__(self, item):
        return "Attr not found: " + item.upper()
    
    def __reversed__(self):
        return self[::-1]
    
    # Regular method to add test scores
    def add_test(self, test_score):
        self.tests.append(test_score)
In [60]:
bob = Student("Bob")
bob.add_test(50)
bob.add_test(80)
bob.add_test(90)
bob.add_test(96)


print ("Bob repr string:", repr(bob))
print("Bob pretty string:", bob)
print ("Length:", len(bob))
print ("__getitem__:", bob.__getitem__(2))
print ("__reversed__:", bob.__reversed__())
print ("Test param:", bob.test_parameter)
Bob repr string: Student (Bob)
Bob pretty string: Student with name of Bob
Length: 4
__getitem__: 90
__reversed__: [96, 90, 80, 50]
Test param: Attr not found: TEST_PARAMETER

Link to code above

Check out more Python Vocabulary on our Glossary Page