Using the enum with mixin classes

The enum module provides the Enum class. One common use case for this class is to define an enumerated domain of values; for example, we might use this to enumerate the four suits for playing cards.

An enumerated type has the following two features:

  • Member names: The member names are proper Python identifiers for the enumerated values.
  • Member values: The member values can be any Python object.

In several previous examples, we've used a simplistic definition for the enumerated members. Here's a typical class definition:

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

This provides four members. We can use Suit.Clubs to reference a specific string. We can also use list(Suit) to create a list of the enumerated members. 

The base Enum class imposes constraints on the member names or values that will be part of the class. We can narrow the definition using mixin class definitions. Specifically, the Enum class can work with a data type as well as additional feature definitions.

We often want a richer definition of the underlying values for the members of the enumeration. This example shows the mixing of str into Enum:

class SuitS(str, Enum):
Clubs = "♣"
Diamonds = "♦"
Hearts = "♥"
Spades = "♠"

The base class is Enum. Features of the str class will be available to each member. The order of the definitions is important: the mixins are listed first; the base class is listed last. 

When str is mixed in, it provides all of the string methods to the member itself without having to make an explicit reference to the internal value of each member. For example, SuitS.Clubs.center(5) will emit the string value centered in a string of length five. 

We can also incorporate additional features in an Enum. In this example, we'll add a class-level feature to enumerate the values:

class EnumDomain:
@classmethod
def domain(cls: Type) -> List[str]:
return [m.value for m in cls]

class SuitD(str, EnumDomain, Enum):
Clubs = "♣"
Diamonds = "♦"
Hearts = "♥"
Spades = "♠"

The following two mixin protocols are added to this class:

  • The str methods will apply to each member directly.
  • The class also has a domain() method, which will emit only the values. We can use SuitD.domain() to get the list of string values associated with the members.

This mixin technique allows us to bundle features together to create complex class definitions from separate aspects. 

A mixin design is better than copy and paste among several related classes.

It can be difficult to create classes that are generic enough to be used as mixins. One approach is to look for duplicated copypasta code across multiple classes. The presence of duplicated code is an indication of a possible mixin to refactor and eliminate the duplication.

Let's see how to write a simple function decorator 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