Python Object-Oriented Python Dice Roller Yatzy Scoring

Kohei Ashida
Kohei Ashida
4,881 Points

AttributeError: 'function' object has no attribute 'items'

I followed along with the code in the lesson but I got back the attribution error below.

>>> from hands import YatzyHand                                                                                                                                           
>>> from dice import D6                                                                                                                                                   
>>> from scoresheets import YatzyScoresheet                                                                                                                               
>>> hand = YatzyHand()                                                                                                                                                    
>>> three = D6(value=3)                                                                                                                                                   
>>> four = D6(value=4)                                                                                                                                                    
>>> one = D6(value=1)                                                                                                                                                     
>>> hand[:] = [one, three, three, four, four]                                                                                                                             
>>> YatzyScoresheet().score_one_pair(hand)                                                                                                                                
Traceback (most recent call last):                                                                                                                                        
  File "<stdin>", line 1, in <module>                                                                                                                                     
  File "/home/treehouse/workspace/yatzy/scoresheets.py", line 13, in score_one_pair                                                                                       
    return self._score_set(hand, 2)                                                                                                                                       
  File "/home/treehouse/workspace/yatzy/scoresheets.py", line 7, in _score_set                                                                                            
    for worth, count in hand._sets.items():                                                                                                                               
AttributeError: 'function' object has no attribute 'items'   

Could anyone help me with fixing this?

dice.py

import random


class Die:
    def __init__(self, sides=2, value=0):
        if not sides >= 2:
            raise ValueError("Must have at least 2 sides")
        if not isinstance(sides, int):
            raise ValueError("Sides must be a whole number")
        self.value = value or random.randint(1, sides)

    def __int__(self):
        return self.value

    def __eq__(self, other):
        return int(self) == other

    def __ne__(self, other):
        return int(self) != other

    def __gt__(self, other):
        return int(self) > other

    def __lt__(self, other):
        return int(self) < other

    def __ge__(self, other):
        return int(self) > other or int(self) == other

    def __le__(self, other):
        return int(self) < other or int(self) == other

    def __add__(self, other):
        return int(self) + other

    def __radd__(self, other):
        return int(self) + other

    def __repr__(self):
        return self.value

class D6(Die):
    def __init__(self, value=0):
        super().__init__(sides=6, value=value)

hands.py

from dice import D6

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

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

    def _by_value(self,value):
        dice = []
        for die in self:
            if die == value:
                dice.append(die)
        return dice

class YatzyHand(Hand):
    def __init__(self, *args, **kwargs):
        super().__init__(size=5, die_class=D6, *args, **kwargs)

    @property
    def ones(self):
        return self._by_value(1)

    def twos(self):
        return self._by_value(2)

    def threes(self):
        return self._by_value(3)

    def fours(self):
        return self._by_value(4)

    def fives(self):
        return self._by_value(5)

    def sixes(self):
        return self._by_value(6)

    def _sets(self):
        return {
            1: len(self.ones),
            2: len(self.twos),
            3: len(self.trees),
            4: len(self.fours),
            5: len(self.fives),
            6: len(self.sixes)
        }

scoresheets.py

class YatzyScoresheet:
    def score_ones(self, hand):
        return sum(hand.ones)

    def _score_set(self, hand, set_size):
        scores = [0]
        for worth, count in hand._sets.items():
            if count == set_size:
                scores.append(worth*set_size)
        return max(scores)

    def score_one_pair(self, hand):
        return self._score_set(hand, 2)

1 Answer

Steven Parker
Steven Parker
201,913 Points

In "scoresheets.py", line 7, there is "hand._sets.items()", but "_sets" is a method (function). To call a method, you need parentheses after the name:

    for worth, count in hand._sets().items():

Otherwise, you could make "_sets" a property, then you don't need to call it using parentheses (probably what was intended).

Kohei Ashida
Kohei Ashida
4,881 Points

Thank you! but scoresheets.py was fine then I found that I forgot putting @property , and made a typo on def _sets(self) in YaztzyHand class.

class YatzyHand(Hand):
    def __init__(self, *args, **kwargs):
        super().__init__(size=5, die_class=D6, *args, **kwargs)

    @property
    def ones(self):
        return self._by_value(1)

    @property
    def twos(self):
        return self._by_value(2)

    @property
    def threes(self):
        return self._by_value(3)

    @property
    def fours(self):
        return self._by_value(4)

    @property
    def fives(self):
        return self._by_value(5)

    @property
    def sixes(self):
        return self._by_value(6)

    @property
    def _sets(self):
        return {
            1: len(self.ones),
            2: len(self.twos),
            3: len(self.threes),
            4: len(self.fours),
            5: len(self.fives),
            6: len(self.sixes)
        }
Kohei Ashida
Kohei Ashida
4,881 Points

I forgot to add my comment here but thanks a lot for the further explanation:)