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

Daniel D'luyz
Daniel D'luyz
2,880 Points

Can't get the length of a hand

Hi !

I am stuck on this question. On the workplace when I execute:

hand = Hand() hand.roll(2) print(hand.total) print(len(hand))

It works well, but the code is not accepted when I click on "Check my work"

Help is appreciated !

Thanks !

dice.py
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, value=0):
        super().__init__(sides=20)
hands.py
from dice import D20


class Hand(list):
    def __init__(self, size=0, die_class=D20, *args, **kwargs):
        self.dice = []
        if not die_class:
            raise ValueError("You must provide a die class")
        super().__init__()

        for _ in range(size):
            self.dice.append(die_class())
        self.sort()

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

    def roll(self, number_of_dice):
        self.__init__(size=number_of_dice)

    def __len__(self):
        return len(self.dice)
Daniel D'luyz
Daniel D'luyz
2,880 Points

Actually, you need to specify that Roll is a @classmethod and return the instance as such :

@classmethod
def roll(cls, number_of_dice):
    return cls(size=number_of_dice)

1 Answer

Steven Parker
Steven Parker
231,269 Points

Daniel is right, except it's a class method you want to implement. And that's enough to pass the challenge.

But since "Hand" is itself an extension of "list", you can add the dice directly to "self" and not need to create a separate "dice" list. Then, you also won't need to redefine "__len__", since the one inherited from "list" will do the job for you.

And .. you also don't need to "sort" the list.

Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

To better understand classmethods, this challenge can be solved without creating a Hand.__init__() method. Since roll is a classmethod, it needs to create and return an instance of the cls. So create an instance, populate it within number of rolled die, and return it. Boom! solved.

By modifying the class Hand.__init__(), a Hand instance can no longer be created without a die class.

Edit: By modifying the class Hand.__init__(), a Hand instance can no longer be contain anything but a D20 or having to use a new parameter in the init, which changes the signature.

The roll classmethod can uniquely create a hand based on a specific D20 class because that is sole the scope of that method.

To keep the solution more generic, consider what would happen if the next Task in the challenge said, "Now create a new classmethod deal such that it can be called as Hand.deal(5) to get a hand of 5 Cards, where Card is a class that contains a random card from a standard 52-card deck." By hardwiring Hand.__init__() to only deal with die_classes it makes the code overly specific.