Making Products Flexible (Part 1)
00:00 In this lesson, you will make some significant changes to the code. So this would be a good time to get a strong cup of coffee if that’s your thing because you will be learning quite a bit.
00:10 The idea is to make the code more flexible. So what is a problem? If you scroll down to the product section, have a look at the XML serializer class on row 40.
00:21
You can see from the .__init__()
method in row 41 that when you instantiate a class, you need a song object. Now what if I want to do something else?
00:31 What if I want to instantiate a book as opposed to a song? So I want to make that a bit more flexible. That will give you a few problems because the attributes on rows 42 to 46 are very specific to songs as titles, as artists.
00:48 So you’ll have to make that more flexible as well. So how will you tackle that? The first problem to solve is that when you instantiate the class, you’d no longer want it to be dependent on whether that’s a song or a book or whatever it is.
01:03
So you want to remove the song
parameter out of the .__init__()
method. So in row 41, well that’s easy enough, just delete song
.
01:14
Well it’s not quite that easy of course, because if song
is no longer there then the code rows 42 to 46 doesn’t work anymore. But for now, let’s just finish the .__init__()
method first.
01:27
Create an attribute that is called _element
as opposed to song
, so it’s more generic,
01:34
and set that element to None
. That is your .__init__()
method. So what happens here is an instance is created and a non-public attribute _element
is created but it’s set to None
.
01:50
That doesn’t give you very much. You will need somehow a way of actually creating the element because currently it is None
. To do that, create a method called def start_object
.
02:05
There’s quite a bit of typing involved so I’ve just copied it in. I’ll talk you through it. A method start_object()
of which the first parameter is self
.
02:14
Then object_name
and object_id
. So this is quite generic because it could be any kind of object with a name and an id. Then, we’re going to assign to .self._element
the specifics of the XML serializer.
02:32
Row 45 is clearly very similar to row 47. Take the element of the element tree, but instead of song
it is object_name
. Because we no longer pass in a song necessarily, it could be a book, and then the attribute dictionary takes object_id
as opposed to song_id
.
02:53 I left row 47 in there just for comparison, but I can now delete that.
03:00
The next step is then to create a method that allows you to add the properties to the element tree. So rows 47 to 50 is what we want to replace. So if you create a method called add_property()
, again I’m just going to copy-paste that in.
03:20
This method will replace the logic in rows 51 to 54 because the logic in rows 51 and 52 is actually repeated in rows 53 and 54 where you add a SubElement
, and then you populate the text attribute of the SubElement
you’ve just added.
03:39 So in rows 51 and 52, you do that for song title and in rows 53 and 54 you do that for the artist. So in rows 48 to 49, you do the same thing but a bit more generically.
03:51
So you add a SubElement
in row 48, and then in row 49 you update the text attribute of that SubElement
.
04:04 So that means you can now delete rows 51 to 54.
04:10
And the final change to make is in your .__str__()
method. In row 52, you see that we are referring to self.song_info
, which doesn’t exist anymore.
04:22
The attribute of our class is now called _element
.
04:28 So you will now do the same thing for the JSON serializer. So scroll up to row 33,
04:35
and what are those changes to make? So firstly, remove song from the .__init__()
method. self.song
will be replaced by self.
04:50
and that is also set equal to None
as was the case for the XML serializer.
04:57
You will again need a start_object()
method because your object is set to None
. So start_object()
first parameter self
, and then object_name
and object_id
.
05:09
And you assign in row 38 the dictionary with key id
and value object_id
to the self.current_object
. You will notice that in row 37, object_name
is input parameter into the start_object()
method, but it is not being used by the code.
05:32
The reason is that you want to keep the structure of the start_object()
method in the JSON serializer the same as the structure of the start_object()
method in the XML serializer.
05:45 And that is why I did the XML serializer first because there the object name was used. But here in the JSON serializer it is not and that is not a problem.
05:58
It just keeps things consistent. So the start_object()
method in row 37 creates a dictionary. What’s left to do now is to add properties to this dictionary.
06:11
The add_property()
method takes self
as its first input parameter, therefore it understands self._current_object
, which is a dictionary as per the code in rows 37 or 38.
06:24
And then you use the name and the value to create key-value pairs in that dictionary. The final change you need to make to the Products
classes is in row 44 in json.dumps()
.
06:40
asdict()
, if you remember, is applied to data classes and self.song
in the previous version of the code was indeed a data class.
06:48
song
is still a data class, but that is no longer what we are passing in to the class. So self.song
doesn’t actually exist anymore.
06:58
It is self._current_object
.
07:05
That is not a data class and therefore, the asdict()
functionality should be removed.
07:13
Also, as you can see in line 38, self._current_object
already is a dictionary, so there is no longer a need to convert it to a dictionary.
07:26 So you have made some drastic changes to the code. In the next lesson, you will make the necessary changes to the rest of the code to make this work.
Become a Member to join the conversation.