How can you extend “in” keyword to a class I made? I am making a card game with a Card class. There is another class which is a Hand of a player. Basically I want to see if a certain card is in a hand. An analogy is below:
>>> 5 in range(0, 5)
True
This is my code. I have a Hand class and I want to see if a Card() is in a Hand()
Also, I’m new to this concept of classes. I’m just starting to understand how this whole thing works. Did I implement len method correctly?
class Card:
def __init__(self, suit, rank):
# self.suit > str
# self.rank > str
if (suit in SUITS) and (rank in RANKS):
self.suit = suit
self.rank = rank
else:
self.suit = None
self.rank = None
print "Invalid card:", suit, rank
def __str__(self):
return self.suit + self.rank
def get_suit(self):
return self.suit
def get_rank(self):
return self.rank
# define hand class
class Hand:
# A list of Card objects
# adding cards to the hand should remove cards from the deck.
def __init__(self):
self.hand = []
def __str__(self):
cards = []
for card in self.hand:
cards += [card.get_suit() + card.get_rank()]
return str(cards)
def add_card(self, card):
return self.hand.append(card)
def __len__(self):
counter = 0
for card in self.hand:
counter +=1
return counter
OK, so I added this code in the hand class:
def __contains__(self, card):
return card in self.hand
but I tried testing my code and it doesn’t work:
c = Card('H','A')
h = Hand()
h.add_card(Card('S','K'))
h.add_card(Card('D','A'))
h.add_card(Card('H','A'))
print 'hand=', h
print 'c=', c
print 'c in h', c in h
It says False in terminal… Why??
@BrenBarn gave you a pointer in the right direction to look at
__contains__. However, as I commented on his answer, implementing that method will probably require that yourCardobjects be comparable. Right now, two cards will only appear equal if they are both the same object.For an example of what I mean, try this:
To fix this, you need to add the
__eq__method to yourCardclass (and probably the__ne__method too, so you’ll be able to use!=tests). Here’s a possible implementation:There’s one other thing I’d like to point out (unrelated to your question). Your
Cardclass has “getter” methods for the suit and rank. Those are usually unnecessary in Python, where you can generally program everything using public variables at first. That is, anything that currently callscard.get_suitshould just accesscard.suitinstead.In less common situation where you need to do complicated things in response to variable access (like calculating certain values when they’re requested, or preventing certain values from being assigned), you can put a
Propertyinstance in the class (usually as a decorator to a function), and external code can still access it just as if it was still a public variable. Code with lots of getters is common in other programming languages which can’t switch between regular variables and Properties like Python can.