4

This is my first cry for help in this site. I have searched for an answer here, but nothing really clears it for me.

I'm trying to learn Python. I've in the "class" chapter. The following code:

class Character:
    def __init__(self, name, initial_health):
        self.name = name
        self.health = initial_health
        self.inventory = []

    def __str__(self):
        s  = "Name: " + self.name
        s += "| Health: " + str(self.health)
        s += "| Inventory: " + str(self.inventory)
        return s

    def grab(self, item):
        self.inventory.append(item)

me = Character("vic", 37)
me.grab("pencil")
me.grab("paper")
print str(me)

...produces:

Name: vic| Health: 37| Inventory: ['pencil', 'paper']

But the following code, which appears to me pretty similar, prints out the memory locations rather than the variables themselves:

import random
SUITS = ['C', 'S', 'H', 'D']
RANKS = ['A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K']
VALUES = {'A':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':10, 'Q':10, 'K':10}

# define card class
class Card:
    def __init__(self, suit, rank):
        if (suit in SUITS) and (rank in RANKS):
            self.suit = suit
            self.rank = rank
            self.value = self.get_value()
        else:
            print "Invalid card: " + str(suit) + str(rank)
    def __str__(self):
        return str(self.suit) + str(self.rank)
    def get_cardDetails(self):
        return self.suit + self.rank + ": " + str(self.value)
    def get_suit(self):
        return self.suit
    def get_rank(self):
        return self.rank
    def get_value(self):
        value = VALUES[self.rank]
        return value

class Hand:
    def __init__(self, card1, card2):
        self.cardCount = 0
        self.cards = []
        self.cards.append(card1)
        self.cardCount += 1
        self.cards.append(card2)
        self.cardCount += 1
        self.value = self.get_value()
        print "Dealed hand: " + str(self.cards[0]) + str(self.cards[1])
        print "Dealed hand: " + str(self.cards)
    def __iter__(self):
        return iter(self.cards)
    def __str__(self):
        return str(self.cards)
    def get_details(self):
        print "Hand: "
        for each in self.cards:
            print " -" + str(each) + ": " + str(each.value)
        s = "Cards: " + str(self.cardCount) + \
               " | Hand: " + str(self.cards) + \
               " | Total Value: " + str(self.value) + " |"
        return s
    def add_card(self, card):
        self.cards.append(card)
        self.cardCount += 1
        self.value = self.get_value()
        print "Added: " + str(card)
    def get_value(self):
        value = 0
        for each in self.cards:
            value = value + each.value
        return value


c1 = Card("C", "2")
c2 = Card("C", "3")
h = Hand(c1, c2)
print str(h)

Output:

Dealed hand: C2C3
Dealed hand: [<__main__.Card instance at 0x00E4F558>, <__main__.Card instance at 0x00E543C8>]
[<__main__.Card instance at 0x00E4F558>, <__main__.Card instance at 0x00E543C8>]

I'm sure I must be missing something here -I'm just learning this after all. Any help will be appreciated. Thanks in advance. And sorry for the long post.

000
  • 26,951
  • 10
  • 71
  • 101
vic
  • 115
  • 1
  • 6
  • 3
    This is the difference between `__str__` and `__repr__` - see this question: http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python - specifically the 'Container’s `__str__` uses contained objects’ `__repr__`' discussion. – Peter DeGlopper Jul 12 '13 at 20:25
  • 1
    More importantly, the `str` of a sequence prints the `repr` of each of its elements. There are a number of questions on this; I'll find one and link to it. – abarnert Jul 12 '13 at 20:25
  • possible duplicate of [Joining a list of python objects with \_\_str\_\_ method](http://stackoverflow.com/questions/5588685/joining-a-list-of-python-objects-with-str-method) – abarnert Jul 12 '13 at 20:26

3 Answers3

6

The __str__ method of a list calls __repr__ on the elements of the list, not __str__. You can either iterate through the list casting the elements to str yourself, or write a Hand class which subclasses from list and defines __str__ to call __str__ on its elements.

llb
  • 1,671
  • 10
  • 14
  • I modified the __str__ method as follows (this is my interpretation of your suggestion) `def __str__(self): c = [] for each in self.cards: c.append(str(each)) return str(c)` Calling the str method now prints the list! I think that's what I wanted... Thank you!! – vic Jul 12 '13 at 21:16
  • @vic That still may not do quite what you want, because you've now called str on a list of strings, which will give you the __repr__ of those strings! Try `def __str__(self): return "[{0}]".format(", ".join(str(item) for item in self.cards))` But if that way is working for you then go with it! – llb Jul 12 '13 at 21:20
  • Ahh... I see what you are saying. Now the output is the string representation of a list, like "["item1", "item2", ...]", instead of ["item1", "item2", ...] -I'll try the __repr__ bit. Thanks again! – vic Jul 12 '13 at 21:29
1

That depends what you are trying to print. In Python if you are printing an object a it is first converted to string by evaluating a.__str__(). If your class has a method __str__ defined, Python uses it. Otherwise it uses the __str__ method from object (in new style classes and in Python 3.x).

Anyway the way the objects are printed depends on how the __str__ method is implemented. If you are evaluating str(els), where els is a list, then Python actually calls List.__str__(lis) and this function is implemented in such a way that it prints repr of objects contained inside. (And function repr returns by default such output as you see.)

If you want to use the objects str methods, you can write:

[str(el) for el in els]

where els is a list of your objects.

kindall
  • 178,883
  • 35
  • 278
  • 309
Wojciech Danilo
  • 11,573
  • 17
  • 66
  • 132
1

Lists print the repr() of their elements, not the str(). Add:

__repr__ = __str__

to your Card class definition. This will make the repr() of your Card class the same as the str() of it, and lists will print your cards as you expect.

You could instead write the __str__ of Hand to take the str() rather than the repr() of list items.

kindall
  • 178,883
  • 35
  • 278
  • 309