Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Start a free Courses trial
to watch this video
Methods, like functions, are better with arguments. Let's see how to make our methods take parameters other than just the instance they're called on.
All of the same rules apply to method arguments as they do to function arguments, with the exception that the first argument has to represent the instance. You can use default values, *args
, and **kwargs
all you want!
Did the 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")
I'm using **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: species
, age
, and 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 color
attribute.
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 height
or 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 __init__
.
class Animal:
def __init__(self, **kwargs):
for attribute, value in 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 its items
method and pull out the two values from each iteration into attribute
and value
variables.
The 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.
So what's the sneakier way than using setattr()
? Every object has an attribute named __dict__
that is a dictionary representation of the writable attributes of an object. You can update dictionaries so you could do:
class Thief:
def __init__(self, name, **kwargs):
self.name = name
self.__dict__.update(kwargs)
Usually, though, you don't want to update .__dict__
directly as it's mostly meant to be a read-only resource. Just because you can write to it doesn't mean you should!
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up