Method Arguments5:33 with Kenneth Love
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,
**kwargs all you want!
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 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.
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!
You need to sign up for Treehouse in order to download course files.Sign up