Using standard library decorators

The standard library has a number of decorators. Modules such as contextlib, functools, unittest, atexit, importlib, and reprlib contain decorators that are excellent examples of cross-cutting aspects of a software design.

One particular example, the functools library, offers the total_ordering decorator that defines comparison operators. It leverages __eq__() and either __lt__(), __le__(), __gt__(), or __ge__() to create a complete suite of comparisons.

First, we'll need this class to fully define a playing card as follows:

from enum import Enum
class Suit(Enum):
Clubs = "♣"
Diamonds = "♦"
Hearts = "♥"
Spades = "♠"

This class provides the enumerated values for the suits of the playing cards.

The following is a variation on the Card class that defines just two comparisons:

import functools

@functools.total_ordering
class CardTO:
__slots__ = ("rank", "suit")

def __init__(self, rank: int, suit: Suit) -> None:
self.rank = rank
self.suit = suit

def __eq__(self, other: Any) -> bool:
return self.rank == cast(CardTO, other).rank

def __lt__(self, other: Any) -> bool:
return self.rank < cast(CardTO, other).rank

def __str__(self) -> str:
return f"{self.rank:d}{self.suit:s}"

Our class, CardTO, is wrapped by a class-level decorator, @functools.total_ordering. This decorator creates the missing method functions to be sure all comparisons work. From some combinations of operators, the remainder can be derived. The general idea is to provide some form of equality (or inequality) test, and an ordering test, and the remainder of the operations can be derived logically from those two.

In the example, we provided < and =. Here's how the other comparisons can be derived:

We can use this class to create objects that can be compared using all of the comparison operators, even though only two were defined as follows:

>>> c1 = Card( 3, '♠' ) 
>>> c2 = Card( 3, '♥' ) 
>>> c1 == c2 
True 
>>> c1 < c2 
False 
>>> c1 <= c2 
True 
>>> c1 >= c2 
True 

This interaction shows that we are able to make comparisons that are not defined in the original class. The decorator added the required method functions to the original class definition.

Let's see how to use standard library mixin classes in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset