A mixed class comparison example
Given a definition of a total for a Hand
object, we can meaningfully define comparisons between the Hand
instances and comparisons between Hand
and int
. In order to determine which kind of comparison we're doing, we're forced to use isinstance()
.
The following is a partial definition of Hand
with comparisons:
class Hand: def __init__( self, dealer_card, *cards ): self.dealer_card= dealer_card self.cards= list(cards) def __str__( self ): return ", ".join( map(str, self.cards) ) def __repr__( self ): return "{__class__.__name__}({dealer_card!r}, {_cards_str})".format( __class__=self.__class__, _cards_str=", ".join( map(repr, self.cards) ), **self.__dict__ ) def __eq__( self, other ): if isinstance(other,int): return self.total() == other try: return (self.cards == other.cards and self.dealer_card == other.dealer_card) except AttributeError: return NotImplemented def __lt__( self, other ): if isinstance(other,int): return self.total() < other try: return self.total() < other.total() except AttributeError: return NotImplemented def __le__( self, other ): if isinstance(other,int): return self.total() <= other try: return self.total() <= other.total() except AttributeError: return NotImplemented __hash__ = None def total( self ): delta_soft = max( c.soft-c.hard for c in self.cards ) hard = sum( c.hard for c in self.cards ) if hard+delta_soft <= 21: return hard+delta_soft return hard
We've defined three of the comparisons, not all six.
In order to interact with Hands
, we'll need a few Card
objects:
>>> two = card21( 2, '♠' ) >>> three = card21( 3, '♠' ) >>> two_c = card21( 2, '♣' ) >>> ace = card21( 1, '♣' ) >>> cards = [ ace, two, two_c, three ]
We'll use this sequence of cards to see two different hand
instances.
This first Hands
object has an irrelevant dealer's Card
object and the set of four Cards
created previously. One of the Card
objects is an ace:
>>> h= Hand( card21(10,'♠'), *cards ) >>> print(h) A♣, 2♠, 2♣, 3♠ >>> h.total() 18
The soft total is 18 and the hard total is 8.
The following is a second Hand
object that has an additional Card
object:
>>> h2= Hand( card21(10,'♠'), card21(5,'♠'), *cards ) >>> print(h2) 5♠, A♣, 2♠, 2♣, 3♠ >>> h2.total() 13
The hard total is 13. There's no soft total because it would be over 21.
The comparisons among Hands
work very nicely, as shown in the following code snippet:
>>> h < h2 False >>> h > h2 True
We can rank Hands
based on the comparison operators.
We can also compare Hands
with integers, as follows:
>>> h == 18 True >>> h < 19 True >>> h > 17 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: Hand() > int()
The comparisons with integers work as long as Python isn't forced to try a fallback. The previous example shows us what happens when there's no __gt__()
method. Python checks the reflected operands, and the integer 17 doesn't have a proper __lt__()
method for Hand
either.
We can add the necessary __gt__()
and __ge__()
functions to make Hand
work properly with integers.