Customizing Objects
00:00
In the previous lesson, I got tangential and pedantic about callables. In this lesson, I’ll show you how to override __str__()
and __repr__()
in your own classes.
00:10
When you define your own class, you are inheriting from Python’s default base class. The base class implements __str__()
and __repr__()
, but you can override these methods for your own purposes.
00:23
In fact, I’d recommend it. The default implementations are beauty-impaired. When you do override these, remember the basic idea outlined at the beginning of this course: __str__()
is for users and __repr__()
is for programmers.
00:37
Back to the REPL. I’m going to start by declaring a class to show you the default implementations of __str__()
and __repr__()
.
00:54
The Book
class has one attribute, a title, which I set in the initializer. Let’s instantiate a book.
01:04 Ooh, scary clown. And now I’ll evaluate the object. See what I mean? Not the prettiest response. In fact, not only is it a little ugly, it also violates the recommendation.
01:16
I can’t eval()
this and get a copy of the book object. Ugly or not, see eye of the beholder, there is some useful information here. The __main__
is because I’m in the REPL.
01:28
That’s the name of the module the class is defined in, and if you define a class in the REPL, the module name is __main__
. Next, it has the name of the class and a hexadecimal value.
01:41
The number in hex is the value of the memory location. Actually, if you convert it to decimal, you’ll find it’s the same value returned by the id()
function that I used in the previous lesson.
01:52
Let’s stringify our book and the result is the same. The base implementation of __str__()
and __repr__()
return the same thing. Time to override a special method. Let’s go to the movies.
02:16
So far, this is similar to the book. Now let’s override the __str__()
method.
02:26
__str__()
takes no additional arguments, but it is a method on a class, so it does need .self
.
02:36 And whatever you return from the method is what gets used when you convert it to a string. You pretty much better return a string otherwise, things might go badly later.
02:45 Using an f-string inside the method is pretty common as you typically want a template containing some of the attributes from the object. Let me create a movie.
02:56 Many of Mr. King’s books became movies. In fact, according to a random factoid site on the internet, 34 of his books became movies. That puts him third. He’s beat out by Agatha Christie, who has 48 and William Shakespeare at a whopping 1,121.
03:14 The factoid page I stole this info off of is a few years old, so the numbers might not be accurate. And this is a tangent in a Python course not a modern cinema class.
03:25
Let’s look at our movie object. Same ugly repr()
, because I didn’t overload it, but when you convert it to a string, the overridden __str__()
gets invoked.
03:38
Let’s try this again with a new class, this time overriding __repr__()
. Seeing the pattern yet? Now for the repr()
,
03:51
like with __str__()
, it takes no additional arguments
04:00
and the best practice is to return a string that could be evaluated to create a new class. Note my use of the !r
in the f-string, so the output will have the value surrounded in quotes.
04:12 Let’s instantiate a song.
04:17
Little David Lee Roth, and there it is in the repr()
caused by the REPL evaluating it. If I copy and paste that, also_song
is a new version.
04:36
Hmm, did you expect that? The examples I showed before were all literals and Python knows how to compare two literals. I haven’t told Python how to compare two Song
objects and because I haven’t, it defaults to checking if they’re the same object, which they are not.
04:57
The comparison mechanism itself is done through a dunder method. I am not going to cover it here, but you could override __eq__()
and change this behavior so comparison worked the way you might expect it to.
05:10 Alright, time for one more.
05:26
When I overrode __repr__()
in Song
, I hardcoded the name of the class. If you change the name of the class, you have to remember to change the string in __repr__()
.
05:37
Instead, you can do what I’ve done here, which is use the .self.__class__
attribute to get at the current object’s class and that class’s .__name__
attribute to get its name.
05:49
Now, if I renamed the Poem
class to Sonnet
, I wouldn’t have to edit my code; it would be correct. Let me create a poem and evaluate it and __repr__()
still works.
06:04 Python 3.7 introduced the idea of a data class. This is to make classes that contain mostly attributes simpler to write. They are a shortcut for writing certain kinds of classes.
06:15
One of the advantages of a data class is it has more useful dunder display methods. To declare a data class, you decorate a regular class. A data class decorator is in the dataclasses
module.
06:33 Now that I’ve imported it, I use it to decorate my new class.
06:42
This declarative form says that the Game
class has an attribute named title that is a string. This shortcut means I don’t need a __init__()
method. Not a big deal, it doesn’t actually save that much code when you’ve only got one thing, but if you have a lot of attributes, this is significantly cleaner.
06:59
And of course, the whole reason I brought it up is a useful default repr()
, which actually is compliant with the recommendation. It also provides a default str()
.
07:14 That’s the core part of the course. Last up, I’ll summarize and point you at other courses you might find interesting.
Become a Member to join the conversation.