1
class Deck:

    def __init__(self):
        self.cards=[]
        for suit in range(4):
            for rank in range(1,14):
                card=Card( suit, rank )
                self.cards.append(card)

    def __str__ (self):
        res=[]
        for card in self.cards:
            res.append(str(card))

        return '\n'.join(res)

    def pick_card(self):
        from random import shuffle
        shuffle(self.cards)
        return self.cards.pop()

    def add_card(self,card):
        if isinstance(card, Card): #check if card belongs to card Class!!
            self.cards.append(card)

    def move_cards(self, gen_hand, num):
        for i in range(num):
            gen_hand.add_card(self.pick_card())


class Hand(Deck):

    def __init__(self, label=''):
        self.cards = []
        self.label = label

    def __str__(self):
        return 'The {} is composed by {}'.format(self.label, self.cards)

mazzo_uno = Decks()
hand = Hand('New Hand')
mazzo_uno.move_cards(hand, 5)
print(hand)

I'm trying to learn objected oriented programming. I have this problem when I try to print the object hand from the subclass Hand(). I got printed something like this <main.Card object at 0x10bd9f978> instead of the proper string name of the 5 cards in self.cards list :

The New Hand is composed by [<__main__.Card object at 0x10bd9f978>, 
<__main__.Card object at 0x10bd9fd30>, <__main__.Card object at 0x10bd9fe80>, 
<__main__.Card object at 0x10bcce0b8>, <__main__.Card object at 0x10bd9fac8>]

I tried also to do this to transform self.cards in string but I get "TypeError: sequence item 0: expected str instance, Card found".

def __str__(self):
    hand_tostr = ', '.join(self.cards)
    return 'The {} is composed by {}'.format(self.label, hand_tostr)

I read on other answers on this site that I should use __repr__ but I didn't understand how to add it in Hand class.

Porridge
  • 107
  • 2
  • 13

1 Answers1

0

__repr__ and __str__ serves different purposes but work the same way.

You can read this to help you chose between the two methods.


You can change the __str__ method of the Hand class like this :

class Hand:

    def __str__(self):
        hand_tostr = ', '.join(map(str, self.cards)) # I use map to apply str() to each element of self.cards
        return 'The {} is composed by {}'.format(self.label, hand_tostr) 

If you want to change the __repr__ method of the Card class, you can try something like this (you didn't provide the code for the Card class)

class Card:
    #your code

    def __repr__(self):
        return <some string>

Now if you do str(<list of Card objects>) it will use the __repr__ method on each card instance to display what you want. I am not a big fan of this solution, for your case I would use the first one as you may want to keep the default representation of a card object for other cases.


Be careful with this code :

def add_card(self,card):
    if isinstance(card, Card): #check if card belongs to card Class!!
        self.cards.append(card)

You don't raise anything if card is not an instance of Card. That means if you use this method with the wrong parameter, error will be hidden and you won't know that the deck has not changed. This is quite dangerous. You can do something like this instead:

def add_card(self,card):
    assert(isinstance(card, Card)), "card parameter of add_card must be an instance of Card class"
    self.cards.append(card)

In a more pythonic way, you can use typehint to inform the user of your classes that card should be an instance of Card. Then trust the duck-typing style of python, or use tools like mypy to verify that the method is correctly used.

Corentin Limier
  • 4,946
  • 1
  • 13
  • 24