Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Intro to Inheritance5:50 with Kenneth Love
Classes are great, but they're even better with parents.
What the heck is
setattr all about?
setattr() usage in this video catch you off-guard? Let's talk about what it is and what it's doing.
First, read the docs about it. I know documentation can sometimes be hard to read, but getting in the habit of reading it, starting there, will help you a lot in the long run.
Now, let's try an experiment. I have a class:
class Animal: def __init__(self, **kwargs): self.species = kwargs.get("species") self.age = kwargs.get("age") self.sound = kwargs.get("sound")
**kwargs here to pack any and all keyword arguments into a dictionary. And then I'll make a wolf using that class.
>>> wolf = Animal(species="Canus Lupus", age=5, sound="howl", color="gray") >>> wolf.species "Canus Lupus"
Great. No errors, Python's happy, I have an instance of my
Animal class. In the
__init__, I set three attributes:
sound. I didn't set
color, though. Is it available?
>>> wolf.color AttributeError...
No, it's not! But there weren't any errors when I created the instance. Why isn't the attribute available?
Well, because I didn't create it. Remember, Python is very explicit. If I don't do something explicitly, Python doesn't do it at all. Since I didn't assign a
color attribute to
self, my instance doesn't have a
This is where
setattr comes in.
setattr lets me set attributes that I don't know about beforehand. I can, of course, go back and explicitly define a
color attribute but what if the next user comes along and she wants a
weight attribute? A year from now,
Animal.__init__ might be hundreds of lines long with attribute declarations! And some of those attributes will only apply to a few animals!
But...if I'm clever and use
setattr, I can just happily accept any and all attributes that someone gives for a particular
Animal instance without having to continually update
class Animal: def __init__(self, **kwargs): for attribute, value in self.kwargs.items(): setattr(self, attribute, value)
So, since I have a handy-dandy
kwargs dict due to using
**kwargs in the method parameters, I can loop through it's
items method and pull out the two values from each iteration into
setattr function takes three arguments: the object to work on, the attribute name to define, and the value to give that attribute. Now, no matter what attribute values I give to my object (assuming they're valid attribute names), my class will happily apply them.
Our single monster is pretty awesome, but let's flesh out the class a bit more and
get some more control over the building of our class instances.
No one wants to fight the same old monster time after time.
Let's let them have a range for hit points and
experience, and a list of colors to pick a random color from.
So once again, we're back in monster.py and editing our Monster class and
let's add some default attributes like we had before.
Before we do that, though, let's import Random.
And then let's add our colors and again this is a constant, and
we'll say yellow and red and blue and green.
You have some favorite colors you'd rather use, go ahead and use those.
And you notice I leave two spaces before my class definition.
Two blank lines rather.
That's just PEP 8 rules, standard Python formatting.
Not required, makes it a little bit easier to read and spot things.
Okay, so let's add our attributes here.
We'll say min hit points equals one,
we'll say max hit points equals one,
min experience equals one max experience equals one oops,
weapon equals sword and sound equal roar.
Just setting up some defaults here.
And then let's take all of these and take them out.
And what we're gonna do is we're gonna do self.hitpoints equals random.rand
int between self.min_hit_points and self.max_hit_points.
And then we're gonna say self.experience is the same thing,
but between self.min_experience and self.max_experience.
And then we're gonna say self.color is equal to random.choice from colors.
So, we get a random color.
And then, just to make sure that everything gets handled.
If anything extra comes in inside quargs.
Let's do for key value and quargs.items and then we're
gonna run set attr and on self, we're gonna set the key to the value.
And then our battle cry stays the same.
So, there's really not a whole lot of new stuff here.
Our monster class has some defaults.
Then we use those in under init to set things like hit points,
experience, and color.
And then in our for loop though, we use a new function called set attr.
Set attr, or
set attribute if you wanna think about it in the non-abbreviated form.
Takes three arguments that are in order,
the object to set the attribute on which is self or the instance,
the attribute that we wanna set which is whatever the key is that they passed in,
and the value to give that attribute which is the value that they passed in.
So we've effectively said that anything in our passed in arguments can
override the attributes already set by our code.
Let's make a monster or two and see how they work now.
So I'm gonna resize this one and we're gonna go back into Python.
And from monster import monster.
And let's go back to our good old friend Jubjub, who's gonna be a monster.
Okay, so Jubjub.hit_points comes back as one.
and Jubjub.color we got blue.
So this Jubjub was randomly created and got a blue one.
So that's basically just our defaults.
Since we get a red [INAUDIBLE] 1 and 1, which has to be 1.
And blue was one of our color options, and we got blue out.
So let's make a new monster where we set some attributes during the creation.
So let's say Jabberwock equals Monster.
Color, we want it to be blue.
And sound, we want it to be whiffling and hit points 500.
And let's set adjective equal to minxim.
See how much of Jabberwocky I can remember.
So jabberwock.color comes out as blue like we told it we wanted it to be.
And jabberwock.hitpoints is 500 which we told it we wanted it to be.
Let's try our battle cry.
WIFLING in all caps.
And then, we added a new thing.
So, adjective isn't one of our attributes that we've been setting.
So, what if I just check adjective?
I get mixin.
Great. So, our arguments worked, instead of,
you know, whatever Python came up with, and
we're able to pass in new items if we want to add new attributes to our objects.
Letting users override defaults is a good way to make your classes more friendly.
Making our instances a little more random will add some flavor to our game too.
I think we've built some pretty solid monsters now.
In our next video,
we're going to create some new monster types based on our monster class.
You need to sign up for Treehouse in order to download course files.Sign up