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

Can anyone help me with solution of this task: Hand.roll(2) and the totall.

The error is can't get the length of Hand. I can't solve it. Thanks in advance.

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


class Hand(list):
    def __init__(self):
        super().__init__()

    def total(self):
        return sum(self)

    def roll(self, size):
        for _ in range(size):
            self.append(D20())
        return self

1 Answer

Eric M
Eric M
11,546 Points

Hi Marym,

Interesting solution. It does get two D20s in hand using certain commands, but instances of the class don't return a value from total.

Total can be fixed easily, just return the @property decorator that you removed.

For the rest, let's look at the requirements:

I'm going to use code similar to Hand.roll(2) and I want to get back an instance of Hand with two D20s rolled in it. I should then be able to call .total on the instance to get the total of the two dice.

Hand.roll(2) needs to return an instance of Hand. Currently Hand.roll(2) returns TypeError: roll() missing 1 required positional argument: 'size' (I highly recommend trying your code out in your own IDE or REPL, the Treehouse client obscures the raw errors in favor of more challenge specific hints).

This error occurs because roll expects two arguments, self and size. Self is only passed when the class has already been instantiated.

Using your code, I can populate a hand if I go to the trouble of writing the following

>>> x = Hand()
>>> x.roll(2)

This is because once instantiated the argument self is inserted in the first position.

Instead we need to have Hand.roll(2) instantiate an instance of the Hand class that's already populated.

For this we can use a Class Method with the @classmethod decorator and return an instance of the class that the method belongs to.

from dice import D20


class Hand(list):
    def __init__(self, hand):
        super().__init__(hand)

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

    @classmethod
    def roll(cls, num_dice):
        new_hand = cls([D20() for x in range(num_dice)])
        return new_hand

I've used a list comprehension here but you could build the list using the same loop that you did in your solution and then pass it to cls. Or you could instantiate an empty cls() within the roll method and append the items as you did before returning the populated object.

The RPG dice roller is a challenge. I think most people to find this to be the toughest part of the Beginning Python course so good work getting so close.

Cheers,

Eric