Mastering Objectoriented Python
上QQ阅读APP看书,第一时间看更新

Designing comparisons

There are two considerations when defining the comparison operators:

  • The obvious question of how to compare two objects of the same class
  • The less obvious question of how to compare objects of different classes

For a class with multiple attributes, we often have a profound ambiguity when looking at the comparison operators. It might not be perfectly clear what we're going to compare.

Consider the humble playing card (again!). An expression such as card1 == card2 is clearly intended to compare rank and suit. Right? Or is that always true? After all, suit doesn't matter in Blackjack.

If we want to decide whether a Hand object can be split, we have to see which of the two code snippets is better. The following is the first code snippet:

if hand.cards[0] == hand.cards[1]

The following is the second code snippet:

if hand.cards[0].rank == hand.cards[1].rank

While one is shorter, brevity is not always best. If we define equality to only consider rank, we will have trouble defining unit tests because a simple TestCase.assertEqual() method will tolerate a wide variety of cards when a unit test should be focused on exactly correct cards.

An expression such as card1 <= 7 is clearly intended to compare rank.

Do we want some comparisons to compare all attributes of a card and other comparisons to compare just rank? What do we do to order cards by suit? Furthermore, equality comparison must parallel the hash calculation. If we've included multiple attributes in the hash, we need to include them in the equality comparison. In this case, it appears that equality (and inequality) between cards must be full Card comparisons because we're hashing the Card values to include rank and suit.

The ordering comparisons between Card, however, should be rank only. Comparisons against integers, similarly, should be rank only. For the special case of detecting a split, hand.cards[0].rank == hand.cards[1].rank will do nicely because it's explicit on the rule for a split.