Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Basic Object-Oriented Python Emulating Built-ins __str__

Why does car_one return the dunder str message?

Hello!

Can someone explain why that when we call the print function on the object 'car_one' the str method gets called?

5 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,423 Points

Hey Isak Landström! Great question! There are specific ways that Python operations on objects (a defined class is an object). The double underscore methods (“dunder methods”) are how a class responds to being referenced in various contexts. All the dunder methods are described in the docs. You may see a one-to-one correspondence from each dunder method to the context it’s called from. Can you see the pattern?

For example, when a class is referenced in a “print” context (via a print statement), the __str__ method is how a class says “if you print me, use the string returned from my __str__ method.

There also are dunder methods for comparing classes, for using classes in math context, etc.

Post back if you need more help. Good luck!!!

Hello, Thank you for the answer and explanation, I just wonder what you mean with the 'one-to-one correspondence pattern' ?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

For each special method there is a corresponding context that calls it:

 Context an object     Method
 x is used in          called

   str(x)             x.__str__()
   f{x}             x.__format__()
   x < y              x.__lt__(y)
   x <= y             x.__le__(y)
   x == y             x.__eq__(y)
   x != y             x.__ne__(y)
   x > y              x.__gt__(y)
   x >= y             x.__ge__(y)
   if x ...           x.__bool__()

Hi Isak!

I'm not sure I fully understand the question.

Why does an instance of a Python class return a dunder string method?

It's just the way Guido van Rossum (the creator of Python) wanted it to work.

To me, it's like asking, "Why is a tangerine called a tangerine?"

Answer: Because that's just what someone somewhere arbitrarily decided it should be!?!

I think the thing to focus on really, is that, if you just print out a class instance object by default you get a pretty basic response, such as:

<__main__.Car object at 0x7ffba860d240>

Which pretty much just tells you that it is a class and its location in memory (not particularly informative).

The takeaway (what's cool), though, is that Python also provides a way to override (overload) that default behavior, by allowing you to explicitly specify what actually prints out, if you print out just the object itself (as opposed to one of its attributes, for example).

Therefore instead of just getting this:

<__main__.Car object at 0x7ffba860d240>

You can get much more useful information when printing the class instance object, such as (in the case of a car object instance):

Ford Mustang 2020 Metallic Blue 

Which is obviously way more interesting, useful, and informative, especially if your aim in printing the object is to somehow identify it and distinguish it from other similar objects.

In fact, depending on how you code the dunder string method, you could even get more details printed out such as:

Type: Car class instance object
Make: Ford
Model: Mustang
Year: 2020
Color: Metallic Blue
License #: XJQR731A

Does that make sense?

I hope that helps.

Stay safe and happy coding!

Hey Peter, thank you for the very thorough explanation, it made a lot more sense now!

Thank you Chris for simplifying this. What I understand is that dunder methods helps us compare and make arithmetic operations on objects that we create and that we can overload these default values in our custom classes that would make sense for that class. Dunder also helps us simplify the code instead of writing alot of methods with double underscores around them. Could we actually use dunder methods instead of the comparison operators like (*, +, -, /, >, <=, >=) but the reason we use these operators is because it makes a cleaner code and less tedious to write?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Correct! The dunder methods allow creating easily read code. All of the built-in type have these dunder methods defined. Try using dir(object) to see all the methods of a type. Below are the dunder and regular methods of a list.

Python 3.3.0 (default, Aug 13 2016, 17:03:14) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on unknown
Type "help", "copyright", "credits" or "license" for more information.
>>> dir(list)
[__add__, __class__, __contains__, __delattr__, __delitem__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __gt__, __hash__, __iadd__, __imul__, __init__, __iter__, __le__, __len__, __lt__, __mul__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __reversed__, __rmul__, __setattr__, __setitem__, __sizeof__, __str__, __subclasshook__, append, clear, copy, count, extend, index, insert, pop, remove, reverse, sort]

Thank you Chris, this information will be very useful in my coming projects.

This is great information. I wish they would have explained the dunder methods this way in the actual course, it's really interesting to understand what's going on behind the scenes with simple commands and where the language is getting the information to process those commands.

Thanks Chris!

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

You’re very welcome. I am happy to help!

(Bummed I didn’t get best answer 🤷‍♂️)