Converting to Product Classes
00:00
The first improvement you will make is to convert the product functions into product classes. Our product functions are on rows 34 and 38. To convert the first one into a class, let’s start by typing the words class
, and then the name is _JSONSerializer
.
00:23
The function, which is now on row 35, takes song
as an input parameter. So you will want to create a class that takes song
as an input parameter as well.
00:34
And you will want to instantiate the class. So we need an __init__()
dunder method. Its first parameter is always .self
, and then song
as a second parameter.
00:46
And all this __init__()
method will do is assign the song
input parameter to the instance attribute .self.song
.
00:56
What will you do with the _serialize_to_json()
function? Well, first of all, let’s convert that into a method by making it part of the class.
01:05
So select both rows, press Tab, and now the def
is within the class. The second thing to do is to then pass in self
instead of song
, because this is now a method, but then thinking about what we’re trying to achieve.
01:20
We are trying to get a string representation of the JSONSerializer
class or of the instance of that class. And that is actually exactly what the __str__()
dunder method is for.
01:32
So if you rename that to __str__()
,
01:38
then that is the __str__()
dunder method. What is left to do for the _JSONSerializer
class is to change song
. As you can see in row 38, change that to self.song
because the self
object is passed into the __str__()
method.
01:55
So self.song
. Now I’m just going to put this on a separate line:
02:03
self.song
for the title, and the artist is self.song.artist
. So just to summarize what is happening, self
is passed into the __str__()
dunder method, and self
represents an instance of the _JSONSerializer
class.
02:23
And that instance contains the song
object as the self.song
instance attribute. Why is that? Because in row 35, the song
object is assigned to the self.song
class attribute.
02:38
Therefore in rows 38, 39 and 40, self.song
is a song
object, which means you have access to song.id
and .artist
.
02:51
So that’s how the JSONSerializer
class works. The next step, of course, is to do the same thing or something very similar for the _serialize_to_xml()
product function on row 43.
03:05
So if you type class
, of course call that _XMLSerializer
,
03:12
you will need an __init__()
method again. So __init__()
self
is a first parameter, song
is the second one, just as before.
03:24 And now there are a few more instance attributes to create. In fact, if you just scroll down a little bit, all these, so lines 46 to 50, you will want to convert to instance attributes.
03:39
So the fastest way to do that that I can think of is to delete the def
, use Tab, and type self
in front of these variable names to convert them to attributes.
03:53
Of course, when you do that, you need to be careful. song_info
is no longer a known variable name, but self.song_info
is because that is what you created on row 44.
04:10
Change that to self.song_info
, and the same thing on row 47. What’s left to do is to create the __str__()
dunder method.
04:24
Again, taking self
as an input parameter, bring the return statement there into the def
, and then song_info
is no longer recognized.
04:35
That becomes self.song_info
. Just for good measure, please add an extra row here. So there you have it. Those are your two product classes. Now there are two things left to do.
04:49
One, please scroll back up to the Creator
. The creator function refers to the _serialize_to_json()
and _serialize_to_xml()
functions on rows 23 and 25.
05:02 Of course, they no longer exist. We’ve replaced them with classes. So we are going to reference the classes here. So I’m just going to copy-paste.
05:15
And then there is the _XMLSerializer
, which I copy from row 42, and then copy that into row 25. So it’s important to understand now that the _get_serializer()
creator returns classes, it does not return instances of classes, it returns classes.
05:35
So how do we get instances of classes? Well, we moved instantiation or execution of functions in the previous step out of the creator and into the serialize()
function.
05:47
So if you move up to the serialize()
function, you will make the second change here. So you now know that the creator function _get_
serializer()
returns a class object.
06:00
So that class object is captured in serializer
_product
in line 13. So in line 14, an instance is then created of that class object by passing song
into it, and then that is returned to the client.
06:17 So you are returning to the client the instance of a product class. Now that is not entirely what the client asks for. The client asks for a string. So how do you create a string representation of a class instance?
06:33
Ha. Well, that is exactly what the __str__()
dunder method allows you to do. So the __str__()
method that you have just implemented in your class allows you to pass a class instance into the str()
function.
06:52
So on line 14, where you return the class instance, you are now going to return a string representation. So you’re going to pass that class instance into the str()
function, just like that.
07:06
So by typing str(
, open parentheses and then the class instance, and then close parentheses. So now that should meet the brief for the client, and all that’s left to do is to see how the code works.
07:20
So if you please save your code and then restart your REPL, and then type the following: from serializer
07:32
import Song
and serialize
,
07:42 which needs an ID, title, and artist,
07:48
and then serialize()
, pass in the song
. So my_song
and choose a format, let’s start with XML, and indeed I get the string representation.
08:03
And let’s pick JSON. There you go, as expected. And then let’s pick something we haven’t implemented yet. And indeed the ValueError
is being raised.
08:19 So that works. Wow, okay. That was quite a lesson. You have managed to do a lot of refactoring under the hood, and that makes your code far more robust. And you have also achieved to not change the interface.
08:35 What was happening in the REPL is exactly the same. So from the point of view of the client, your tinkering and code improvements have not changed the client experience.
08:46 So that is great work, well done. In the next lesson, you’ll make the code just a little bit more Pythonic by looking at data classes.
Become a Member to join the conversation.