Python _Str_ and Lists

Python __str__ and lists

Calling string on a python list calls the __repr__ method on each element inside. For some items, __str__ and __repr__ are the same. If you want that behavior, do:

def __str__(self):
...
def __repr__(self):
return self.__str__()

__str__ method on list of objects

You just need to replace the __str__ method of the PlayingCard class with a __repr__ method:

class PlayingCard():

def __init__(self,value,suit):
self.value = value
self.suit = suit

def __repr__(self):
return '{} of {}'.format(Value(self.value).name, Suit(self.suit).name)

Alternatively you can change the __str__ method in the Deck class to get the string representation of every card:

class Deck():

def __init__(self):
self.cards=[PlayingCard(val,suit) for val in Value for suit in Suit]

def __str__(self):
return str([str(card) for card in self.cards])

Then you get the correct output with:

...

deck = Deck()
print(deck)

Output:

(The 2nd way will add quotes around every printed card)

[Two of Spades, Two of Hearts, Two of Clubs, Two of Diamonds, Three of
Spades, Three of Hearts, Three of Clubs, Three of Diamonds, Four of
Spades, Four of Hearts, Four of Clubs, Four of Diamonds, Five of
Spades, Five of Hearts, Five of Clubs, Five of Diamonds, Six of
Spades, Six of Hearts, Six of Clubs, Six of Diamonds, Seven of Spades,
Seven ofHearts, Seven of Clubs, Seven of Diamonds, Eight of Spades,
Eight of Hearts, Eight of Clubs, Eight of Diamonds, Nine of Spades,
Nine of Hearts, Nine of Clubs, Nine of Diamonds, Ten of Spades, Ten of
Hearts, Ten of Clubs, Ten of Diamonds, Jack of Spades, Jack of Hearts,
Jack of Clubs, Jack of Diamonds, Queen of Spades, Queen of Hearts,
Queen of Clubs, Queen of Diamonds, King of Spades, King of Hearts,
King of Clubs, King of Diamonds, Ace of Spades, Ace of Hearts, Ace of
Clubs, Ace of Diamonds]

When you call __str__ on a list object, it will go through every element of the list and call __repr__ on that object to get its representation.

So when you call print(deck), you get:

--> deck.__str__()
--> str(self.cards)
--> [card.__repr__() for card in self.cards]

Confused about __str__ on list in Python

Python has two different ways to convert an object to a string: str() and repr(). Printing an object uses str(); printing a list containing an object uses str() for the list itself, but the implementation of list.__str__() calls repr() for the individual items.

So you should also overwrite __repr__(). A simple

__repr__ = __str__

at the end of the class body will do the trick.

How do I use __str__ method to print list?

__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.

Is there a way to use __str__ in a class but returning a list?

The builtin str() function will raise a TypeError if it calls your __str__ and gets something that isn't a string, and you won't convince it to do otherwise.

What you probably want is for Vec.__str__ to return the string representation of data, rather than data itself:

class Vec:
def __init__(self, data: list) -> None:
self.data = data

def __str__(self) -> str:
return str(self.data)

The __str__ method has no bearing on your other use case:

for example if I want to multiply Mat with a Vec I would have to do Mat * Vec.data or Mat * Vec.T (T stands for transposed) which I dont like and I would just like to type Mat * Vec in case I dont need to transpose the vector.

This should instead be addressed in Mat.__mul__ (which should operate on a Vec, not the underlying list) and Vec.T/Vec.Transpose (which should return a Vec, not a list):

class Vec:

...

def Transpose(self) -> 'Vec':
vec = self.Create(len(self.data), len(self.data[0]), 0)
for i in range(len(self.data)):
for j in range(len(self.data[0])):
vec[j][i] = self.data[i][j]
return Vec(vec)

class Mat:
...

def __mul__(self, vec: Vec) -> list[list[int]]:
if not self.CheckRowCol(vec.data):
raise MatrixRowColError

mat3 = self.Create(len(vec.data[0]), len(self.data), 0)

for i in range(len(self.data)):
for j in range(len(vec.data[0])):
for k in range(len(self.data[0])):
mat3[i][j] += self.data[i][k] * vec.data[k][j]

return mat3

Now you can indeed do Mat * Vec or Mat * Vec.T and it will do the right thing.

Note that it would probably be better for Mat.__mul__ to return a Mat, but you haven't provided a constructor that makes it easy for me to implement that part -- nevertheless I hope this gives you a better way to think about your class interfaces and how they can make it easier (or harder) to use the class! Ideally the user of the class shouldn't even be able to access the internals, much less be forced to.

Unrelated to this, I'd suggest spending a bit of time learning about Python's list comprehension syntax, because it'll save you a lot of list allocation boilerplate (i.e. your various Create methods). :)

How to apply __str__ function when printing a list of objects in Python

Try:

class Test:
def __repr__(self):
return 'asd'

And read this documentation link:

Python - __str__ returning elements of a list

Suppose this is your Card class:

class Card(object):
# has self.value and self.suit

def __str__(self):
return (str(self.value) + self.suit)

So your player class is something like this:

class Player(object):
# has self.card1, self.card2

def __str__(self):
return "Player's Cards %s %s (Total %d)" % (
self.card1, self.card2, self.__sum_of_cards()
)

So, all you need is to add the missing method __sum_of_cards in Player:

def __sum_of_cards(self):
return self.card1.value + self.card2.value

You could do this directly in __str__ instead of implementing __sum_of_cards, but I'm assuming it means something if you're printing it, and that implies it will be needed elsewhere as well.

Edit:

Same goes for lists:

class Player(object):
# has self.hand

def __str__(self):
return "Player's Cards %s (Total %d)" % (
",".join(str(card) for card in self.hand),
self.__sum_of_hand()
)

But a different __sum_of_hand is needed:

def __sum_of_hand(self):
return sum(x.value for x in self.hand)


Related Topics



Leave a reply



Submit