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 trialAnthony Grodowski
4,902 PointsA big confusion in a challange
Why am I getting an output like this? It seems like cls() is removing all of the values inside list_sum. Why?
>>> from hands import Hand
>>> from dice import D20
>>> Hand.roll(2)
[12, 17]
[12, 17]
[]
[12, 17]
[12, 17]
[]
import random
class Die:
def __init__(self, sides=2):
if sides < 2:
raise ValueError("Can't have fewer than two sides")
self.sides = sides
self.value = random.randint(1, sides)
def __int__(self):
return self.value
def __add__(self, other):
return int(self) + other
def __radd__(self, other):
return self + other
class D20(Die):
def __init__(self):
super().__init__(sides=20)
from dice import D20
class Hand(list):
def __init__(self, list_sum=None):
self.list_sum = list_sum
print(self.list_sum)
print(list_sum)
@classmethod
def roll(cls, times):
list_sum = []
for _ in range(times):
list_sum.append(D20().value)
print(cls(list_sum))
return cls(list_sum)
@property
def total(self):
return sum(self)
1 Answer
Chris Freeman
Treehouse Moderator 68,457 PointsBy adding numbers to the print statements, you can follow the flow:
class Hand(list):
def __init__(self, list_sum=None):
self.list_sum = list_sum
print(1, self.list_sum)
print(2, list_sum)
@classmethod
def roll(cls, times):
list_sum = []
for _ in range(times):
list_sum.append(D20().value)
print(3, cls(list_sum))
return cls(list_sum)
@property
def total(self):
return sum(self)
a= Hand.roll(2)
print(4, a)
Produces:
1 [5, 8]
2 [5, 8]
3 []
1 [5, 8]
2 [5, 8]
4 []
The print before the return
and the return
both create instances of Hand
The instance from the print is thrown away.
Anthony Grodowski
4,902 PointsAnthony Grodowski
4,902 PointsThanks Chris, I still don't understand, why
cls()
makeslist_sum
to loose it's content. Could you please explain it to me?(sorry if it's already in your answer and I can't see it)Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsAdding a few more prints:
Produces:
Printing the instance which is an extension of
list
produces the empty list since nothing was append toself
. The custom added attributelist_sum
does display as printed.Anthony Grodowski
4,902 PointsAnthony Grodowski
4,902 PointsThanks Chris! I've played a bit with that code and I came to a conclusion that I completely don't need
self
in my code. I was struggling with understanding your answer above becasue I didn't get how isself
neccessary in this code. Did you mean by sayingself
thecls()
? Because then it would make sense. I finally undertand the point of having@classmethod
- they don't need an instance to work on. Am I getting that right? Here's my code:...and the output:
EDIT After a minute I realised that in
there's
self
! How is it possible that it still works even tho I removed everything with conection to the instance from the code? Isself
andcls()
basically the same thing? I came to that conclusion after changingself
tocls
inAlso I don't understand what's the difference between just
cls
andcls()
Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsGood point!
self
andcls
are similar in that they are both placeholders used to bind the method to an object. "Binding" means to attach the method to an instance or a class that the method will use as a context to operate within.Both of the terms
self
andcls
are always used as the first positional parameter. For class methods, thecls
is assigned when the class is parsed. for instance methods, theself
is assigned during the instance creation.The names of the parameters
self
andcls
are a Python convention. Changing the name of the first positional argument to something else does not change the functionality, rather it only affects the readability of the code. So changingself
tocls
in thetotal
method does not affect it's functionality. In the method withself
changed tocls
, the parametercls
will still be assigned to point to the instance of the class.By adding
print
inside thetotal
method, you can see whether it isself
orcls
, the value of the parameter is the same. In fact, you could you "smith
" and "agent
" instead ofself
andcls
as the name of the positional arguments.Anthony Grodowski
4,902 PointsAnthony Grodowski
4,902 PointsOh alright, so as long as I'm consistent in naming these parameters, functionality isn't affected. Only readabilty is... So which way is proper? Should I in the
@classmethod
usecls
and in thetotal
method useself
? But then constintacy rule is enroached and to me it doesn't make sense to in one part of a code name it in a different way than in an another part...Also while testing the code one thing suprised me: how does python know that when calling
return sum(cls)
we want python to return the summed value ofD20()
attribute.value
? I mean I didn't provide an information that I want.value
attribute to be summed.Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsShould I in the @classmethoduse cls and in the total method use self? Yes! Though it may look inconsistent, the point of using
cls
in a classmethod is to provide a visual reminder that you are operating on the class and not on an instance of the class.How does python know that when calling
return sum(self)
we want python to return the summed value of D20() attribute .value? The sum() function expects an iterable. Since theself
instance is derived fromlist
,sum()
will be able iterated over each item in theHand
instance and calling the item's__add__
method. In this case, it calls theD20
instance__add__
method, which returns anint
.