Functional Python Programming

(Wang) #1
Chapter 10

Defining classes with total ordering


The total_ordering decorator is helpful for creating new class definitions that
implement a rich set of comparison operators. This might apply to numeric classes
that subclass numbers.Number. It may also apply to semi-numeric classes.


As an example of a semi-numeric class, consider a playing card. It has a numeric
rank and a symbolic suit. The rank matters only when doing simulations of some
games. This is particularly important when simulating casino Blackjack. Like
numbers, cards have an ordering. We often sum the point values of each card,
making them number-like. However, multiplication of card × card doesn't really
make any sense.


We can almost emulate a playing card with a namedtuple() function as follows:


Card1 = namedtuple("Card1", ("rank", "suit"))


This suffers from a profound limitation: all comparisons include both a rank
and a suit by default. This leads to the following awkward behavior:





c2s= Card1(2, '\u2660')
c2h= Card1(2, '\u2665')
c2h == c2s
False





This doesn't work well for Blackjack. It's unsuitable for certain Poker simulations also.


We'd really prefer the cards to be compared only by their rank. Following is a much
more useful class definition. We'll show this in two parts. The first part defines the
essential attributes:


@totalordering
class Card(tuple):
slots = ()
def new( class
, rank, suit ):
obj= tuple.new(Card, (rank, suit))
return obj
def repr(self):
return "{0.rank}{0.suit}".format(self)
@property
def rank(self):
return self[0]
@property
def suit(self):


return self[1]

Free download pdf