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 trial
Anthony 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,468 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_sumto 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,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsAdding a few more prints:
Produces:
Printing the instance which is an extension of
listproduces the empty list since nothing was append toself. The custom added attributelist_sumdoes 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
selfin my code. I was struggling with understanding your answer above becasue I didn't get how isselfneccessary in this code. Did you mean by sayingselfthecls()? 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? Isselfandcls()basically the same thing? I came to that conclusion after changingselftoclsinAlso I don't understand what's the difference between just
clsandcls()Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsGood point!
selfandclsare 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
selfandclsare always used as the first positional parameter. For class methods, theclsis assigned when the class is parsed. for instance methods, theselfis assigned during the instance creation.The names of the parameters
selfandclsare 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 changingselftoclsin thetotalmethod does not affect it's functionality. In the method withselfchanged tocls, the parameterclswill still be assigned to point to the instance of the class.By adding
printinside thetotalmethod, you can see whether it isselforcls, the value of the parameter is the same. In fact, you could you "smith" and "agent" instead ofselfandclsas 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
@classmethoduseclsand in thetotalmethod 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.valueattribute to be summed.Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsShould I in the @classmethoduse cls and in the total method use self? Yes! Though it may look inconsistent, the point of using
clsin 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 theselfinstance is derived fromlist,sum()will be able iterated over each item in theHandinstance and calling the item's__add__method. In this case, it calls theD20instance__add__method, which returns anint.