Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialJustin Noor
3,692 PointsWhat's the point of __init__ and **kwargs if we are assigning so many attributes to the individual classes/subclasses?
I am totally lost on this part of OOP.
Below is the code from the previous lecture. What's the point of using init and **kwargs if we are manually assigning so many attributes to these classes/subclasses anyways? It just seems messy.
import random
COLORS = ['yellow', 'red', 'blue', 'green']
class Monster:
min_hit_points = 1
max_hit_points = 1
min_experience = 1
max_experience = 1
weapon = 'sword'
sound = 'roar'
def __init__(self, **kwargs):
self.hit_points = random.randint(self.min_hit-points, self.max_hit_points)
self.experience = random.randint(self.min_experience, self.max.experience)
self.color = random.choice(COLORS)
for key, value in kwargs.items():
setattr(self, key, value)
def battlecry(self):
return self.sound.upper()
class Goblin(Monster):
max_hit_points = 3
max_experience = 2
sound = 'squeak'
class Troll(Monster):
min_hit_points = 3
max_hit_points = 5
min_experience = 2
max_experience = 6
sound = 'growl'
class Dragon(Monster):
min_hit_points = 5
max_hit_points = 10
min_experience = 6
max_experience = 10
sound = 'raaaaaar'
2 Answers
Gerald Wells
12,763 PointsThe first thing I want to point out, you have an semantic error inside __init__
, more specifically on self.experience.
you had set self.experience = random.randint(self.min_experience, self.max.experience)
self.max.experience
calls the fxn max()
instead of the intended use of self.max_experience
being a variable, be careful with certain naming techniques they can cause undo stress.
corrected:
import random
COLORS = ['yellow', 'red', 'blue', 'green']
class Monster(object):
min_hit_points = 1
max_hit_points = 1
min_experience = 1
max_experience = 1
weapon = 'sword'
sound = 'roar'
def __init__(self, **kwargs):
self.hit_points = random.randint(self.min_hit_points, self.max_hit_points)
self.experience = random.randint(self.min_experience, self.max_experience)
self.color = random.choice(COLORS)
print(self.hit_points, self.experience, self.color)
for key, value in kwargs.items():
setattr(self, key, value)
def battlecry(self):
return self.sound.upper()
class Goblin(Monster):
max_hit_points = 3
max_experience = 2
sound = 'squeak'
class Troll(Monster):
min_hit_points = 3
max_hit_points = 5
min_experience = 2
max_experience = 6
sound = 'growl'
class Dragon(Monster):
min_hit_points = 5
max_hit_points = 10
min_experience = 6
max_experience = 10
sound = 'raaaaaar'
if __name__ == '__main__':
tim, gerald, drew, patty = Monster(), Goblin(), Troll(), Dragon()
john = Goblin
Start by copying the above code and running it.
What is__init__
?
Most if not all classes by default contain the __init__
function, it is commonly refereed to as a "class constructor". When a class is initialized the __init__
fxn whether you overrode the fxn or not is run. It constructs the class on initialization....for example:
The output of the above code:
1 1 blue
1 2 blue
4 4 green
7 7 green
You can run this code multiple times and the output could be different every time thanks to __init__
.
Did you notice that john = Goblin
didn't have an output?(explanation below)
How does this pertain to the code above?
Above we set gerald = Goblin()
which is different from when we set john = Goblin
. Lets call gerald case#1 and john case#2, in case#1 the class is initialized and in case#2 just the opposite. If you tried to call john.color
since the class wasn't initialized python would throw an error AttributeError: type object 'Goblin' has no attribute 'color'
on the flip side gerald.color
would return a randomly generated value from the list COLORS.
However you can still initialize case#2 by john()
, at this point __init__
is called.
Class inheritance
Monster is what's called a super class or parent class, values in it will be inherited by the classes Dragon, Troll, and Goblin.
Dragon, Troll, and Goblin are referred to as a child class or a child of Monster since they inherit certain attributes from Monster.
**kwargs
**kwargs
is a place holder variable that allows you to pass an undetermined number of variables to it. For instance since you aren't passing minimum values to the parent class from Goblin, you use **kwargs
to prevent TypeError $FUNCTION() missing $NUM required positional arguments
from occurring. By using **kwargs
you are saying you are going to pass an indiscriminate number of variables to the function.
What's the point of using init and **kwargs if we are manually assigning so many attributes to these classes/subclasses anyways?
If you notice, you aren't assigning direct values to your classes you are passing parameters to the parent class which are calculated by the fxn __init__
upon initialization.
I hope I have answered your question, please let me know if you need further clarification.
Recommended reading:
- Fundamentals of Python: First Programs by: Kenneth A. Lambert
-Fundamentals of Python: Data Structures by: Kenneth A. Lambert
- Functional Programming by Bruce Maclennan
- Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. “Uncle Bob” Martin
Justin Noor
3,692 PointsHi Gerald. I appreciate you taking the time to reply. Thanks for spotting out that type as well. I don't think I made my question very clear. My bad, I was kind of rattled and I typed it on a whim.
I'm relatively clear on the the constructor init , and **kwargs, just not totally clear on the way they are used in the video.
The video uses the constructor init(self, **kwargs) only for three attributes, and then hard codes another 5 or 6 attributes in each of the remaining classes. It just doesn't seem very Pythonic to use the constructor if you're going to hard code the classes anyways.
I might be missing something. I need to re-watch with fresh eyes.
Gerald Wells
12,763 PointsI think at that point its more functionality based. If you are creating a game you need some randomization, without it the difficulty decreases. I haven't done this course in a while, but later on today I will go through the videos to see if I can get a better understanding of your confusion.