Join us and get access to thousands of tutorials and a community of expert Pythonistas.
This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.
Use a Dunder Class Reference
00:00
I’ve just coded up .__str__() and I’ve used the .animal_type, which is a class attribute in my classes, but I’m accessing it through the instance.
00:09 So I want to show you what kind of troubles you can run into when you do that and also a solution for it.
00:16
Restart, and I will create the Dog, d again. Okay, of course now we’re running into an error because I added trait as a required parameter.
00:28
So now it’s not just "brown" and called "Puppy", but it’s also not lazy at all. It’s—what’s the opposite of lazy?—industrious.
00:42
Okay, so we have d.trait. We have our industrious brown dog Puppy, and if I print() the Dog now, the Dog instance, I should get back the string, and it says "The industrious brown dog Puppy jumps over the lazy dog."
00:59
That’s the output that I was hoping for. But now I want to redo the little problem that I did earlier. If I assign a new instance attribute on this Dog object that shadows, the class attribute .animal_type, then Python’s going to pick up that one first, and it’s not going to go back to the class attribute .animal_type.
01:20
So let’s say d.animal_type = "fox" and then print() the Dog object again.
01:28
Then you see that it says "The industrious brown fox Puppy jumps over the lazy dog", which is closer to the original sentence, but it’s not what we want.
01:36 I want to make sure that in this output, I always still know that the instance is actually a dog and not a fox, even if I would accidentally add this instance attribute that shadows the class attribute.
01:50
But I don’t want to go into each of those child classes and implement a new .__str__() method, where I then put in the .animal_type directly from the class.
02:04
So instead of self.animal_type or Animal.animal_type, I’m going to say self.__class__.animal_type, and this self.__class__ is going to always refer to the class that this instance was modeled from.
02:21
In the Dog class, this is going to be Dog, and in the Pig class it’s going to be Pig, et cetera, so that the .animal_type is actually going to be the class attribute, even if you accidentally override it and put an instance attribute of the same name in there.
02:37 Long story short, let’s try it out.
02:43
Again, we need our "Puppy".
02:49
Try it out first. print(d) still working. "The industrious brown dog Puppy jumps over the lazy dog." Great. And then if I create this instance attribute, .animal_type, that shadows the class attribute, now if I print(d),
03:04
you can see that it still prints out dog. It doesn’t take the instance attribute .animal_type, but it still refers back to the class attribute.
03:13
So, a little hoop that I jumped through here just to make sure that I can also print() out what type of animal an animal is and to keep this class attribute around without having to do a lot of code duplication.
03:27 There might be other ways to solve this, but I think this works well, and it was a nice chance to talk about some potential issues with class attributes.
03:36
All right, Sheep, Dog, and Pig can all have .name, .color, and .trait and can print() out nicely.
Become a Member to join the conversation.