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

Python Object-Oriented Python Dice Roller RPG Roller

Sebastiaan van Vugt
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Sebastiaan van Vugt
Python Development Techdegree Graduate 13,554 Points

Need help using classmethod

My code is the following:

from dice import D20

class Hand(list):       
    def __init__(self, times):
        self.times = times        

    @classmethod
    def roll(cls, times):
        list = []        
        for _ in range(times):            
            list.append(D20())
            print(list)
        return cls(list)
    print(30*"*")   
    print(list)
    print(30*"*")  

    @property
    def total(self):
        return sum(self)

rt = Hand.roll(3)
print(rt.total)

The list is correctly generated but can then not be made available to the total method. I must be doing something wrong but I do not know what. Any help is appreciated. Thank you.

1 Answer

I was able to make it work by calling super to initiate a list with dice objects:

class Hand(list):

    def __init__(self, dice=None):
        super().__init__(dice)

Although Hand inherits list, it does not contain any values unless they are added. Where you have

        return cls(list)

this instantiates the Hand class, but the list was actually stored in the times class variable and not passed up to the list super class.

Additionally, times is not needed as a class variable as it is a parameter in roll().

Sebastiaan van Vugt
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Sebastiaan van Vugt
Python Development Techdegree Graduate 13,554 Points

Thank you for your help.

I finally got it to work like this:

from dice import D20

class Hand(list):
    @classmethod
    def roll(cls, times):
        list = []        
        for _ in range(times):            
            list.append(D20())
        return cls(list)

    @property
    def total(self):
        return sum(self)

It seems I indeed should not override the "times" variable.

A few things I found confusing though and I would like to ask a few follow-up questions. The first is about the list inheritance which is not a real inheritance since we don't have a list class. This seems to be simply a way to specify that the output should be a list. Is that right?

Furthermore, I don't understand what is happening with your init and super. "dice" is the name of the file and not that of a method or variable. Do I understand correctly that we usually use super to make a variable available in the parent class?

I was also long puzzled by the @classmethod but read that it would be appropriate in this situation and maybe now I understand why. I believe that we don't need to pass on anything to the dice app as long as we import the D20 method ("from dice import D20"). Since we however want to pass the variable (number of) "times" in the fashion "Hand.roll(3)" we need to use classmethod I believe. Simultaneously the output then becomes available to the total method. What is your take on this?

list is in fact a class that we have. It may not be in your file, and you may not import it, but it is a class built in to python. More info about lists here.

The way I think about inheritance is this: A list is the most generic possible collection of objects. It has methods to add things, delete them, and so on and so forth. If we make a class that inherits the list class, it inherits all of these generic traits. It also becomes a collection of objects that has all of the properties of a list. However, in addition, we can add methods and properties to this new class, making it a special type of the list.

For example, your Hand class is a list but it also has the roll method, and a property called total. It is just a special case of a list with an added method and property.

As for the use of super(), this is used to access a method of the parent class. Hand is a child class of the list, and thus inherits all of its methods and properties. However, in order to access them, we have to make a call to the parent class using super(). So when I call

def __init__(self, dice=None):
    super().__init__(dice)

what i am doing is initializing an instance of the class, using the super class' constructor. This creates our hand, with the same generic structure as the list, but also having the methods we have created, and being of type Hand.

Finally, for class methods, I look at these like object factories. A class method lets you easily create an instance of your class. By calling

hand.roll(3)

we avoid the steps of individually creating each new dice object, then adding them to the hand. Instead, calling Hand.roll(x) will always immediately instantiate a Hand with x D20 objects. A class method always returns an instance of the class, so they are great for this purpose.

I hope this helps.