Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Introducing Dunder Methods

In this lesson, you’ll learn about dunder methods. They’re super useful, and there are lots of them! To learn more about them, check out the documentation.

00:00 Dunder methods, also called special instance methods, which is the more official name, but casually in Python, they’re called dunder methods. Whether it’s a good name or not, I don’t know, but that’s the name that has stuck.

00:14 So what are dunder methods, and what are they used for? When you have a list, for example, say you have a names, and you have a bunch of names in that list, and then you try and print the names and you get a nice representation of that list with all the values in that list.

00:34 But you’ve been instantiating objects recently. Say if you have a miles object, and you’ve instantiated that with a name, "Miles", and an age, say 4. If you try and print this, you get this horrible monstrosity. Well, it’s not a horrible monstrosity, but you get the point.

00:53 It doesn’t give you much information about the actual object. It just says that it’s an object. It could have attributes. It could have methods. We don’t know. It’s not giving us very much information.

01:05 So this is where dunder methods comes in. There are many dunder methods, but one of the dunder methods that is useful in this case is the .__str__() method. Here is the class that you’ve been using so far, Doggo. The functions here are just abbreviated.

01:22 You can imagine that there’s the code that you’ve been working on so far is in here. And if you just add a .__str__() method, this will now be used whenever you call the print() function.

01:39 Now, there are few rules for dunder methods. They should take certain arguments and return certain types of values. The .__str__(), which is short for string, should return a string.

01:51 So basically this allows us to say, whenever someone calls print() on an instance of a Doggo, we want this to be the representation that they see.

02:02 And so you’ve made an f-string here, you get the .name and the .age, and you say "{} is {self.age} years old", whatever that may be in that instance. What does that look like in practice?

02:16 You instantiate your object, Doggo("Miles", 4) years old, and now you want to print miles. So what are you going to get? 'Miles is 4 years old'.

02:27 Whether this is a good idea to have this type of message whenever you print this object, that’s open to question, but the fact is that you can customize it to whatever you want.

02:38 So let’s look at another example. Say you’ve got the Point class, and here we’re abbreviating the .__init__() constructor, as we’ve already gone through it, and we’re going to add two dunder methods to the Point class.

02:50 One is add, .__add__(), and the other is the one that you added to the Doggo class, .__str__(). So if you look at the .__str__() one first, you’ll see that you’re just returning "Point at x", and you’re using the .x value, "y", and you’re using the .y value. So it’s a nice representation.

03:11 It says whenever you print this, it will say 'Point at x: 0, y: 0', for instance. So it’s very clear what it is. It’s saying, I’m a point, and these are my attributes, or these are the most important attributes that help whatever it is that you’re doing. Maybe you use this for debugging mainly, but the fact is that you can customize this to whatever you want.

03:32 The .__add__() one is slightly different though. The .__add__() takes another argument. Sometimes that’s called other. You can call that whatever you want.

03:40 It’s kind of like self. It’s very common to call it other. And what this will allow you to do is take that other and change the attributes of the instance using the attributes of the other instance.

03:53 So here, what you’ve done is you’re taking self.x + other.x, which you assume to be a point, and self.y + other.y, and you’re assigning these to the instance attributes of that instance. So let’s see how that works out in practice.

04:14 You’ve got your center—say you’re calling the center 50, 50 now—and let’s print it with this new dunder method. 'Point at x: 50, y: 50'. And that’s very descriptive of what it is.

04:27 Let’s look at how the .__add__() dunder method behaves. So say you had another point, say distance, and you defined Point(25, 25), and then you say center + distance.

04:41 Now you can’t usually use this with classes. You can’t just add a class together. It doesn’t know what to do, but if you’ve defined this special dunder method, the .__add__() one, then this will work. And when you print center, you’ll see that 25 has been added to the original 50, and the 25 of the Y axis has also been added to 50, so you end up with 75, 75 in the final object.

05:10 So to sum up, dunder is jargon for double underscore. They’re also called special instance methods. They can be used to override basic behavior of operators or certain functions, like the print() functions, so you can have a representation as a string.

05:27 You can change the behavior with operators such as +. There are lots of dunder methods. Check out the documentation for more information on those.

05:37 They can really take your classes to the next level.

mikikop on April 23, 2023

Hello on the course about class, the lecturer gives an example of a class Doggo where you have 2 instance methods returning strings (one description and one speak) then he implements the dunder method str by returning the string of the description instance method. what about the string of the speak instance method? can have 2 dunder str method in the same class?? i think no but how to return the string of the speak dunder method in a good representation?? thanks

Bartosz Zaczyński RP Team on April 24, 2023

@mikikop You’re intuition is right, as you can have at most one method with the same name in a Python class. It’s technically possible to overload a method by changing its signature, i.e., the list of parameters, and using a special decorator or a metaclasses, but that’s fairly advanced and rarely done in practice.

The goal of the .__str__() method is to provide a textual description of the object at hand for the human. Therefore, you can replace your custom .description() method with this dunder special method.

On the other hand, the .speak() method in the class seems to be more specific and perform a particular task rather than describe the object.

Become a Member to join the conversation.