Creating enumerated constants

We can define classes for the suits of our cards. The suits of playing cards are an example of a type with a domain that can be exhaustively enumerated. Some other types with very small domains of values include the None type, where there's only one value, and the bool type, which has only two values.

The suit of a playing card could be thought of as an immutable object: the state should not be changed. Python has one simple formal mechanism for defining an object as immutable. We'll look at techniques to assure immutability in Chapter 4, Attribute Access, Properties, and Descriptors. While it might make sense for the attributes of a suit to be immutable, the extra effort has no tangible benefit.

The following is a class that we'll use to build four manifest constants:

from enum import Enum


class Suit(str, Enum):
Club = "♣"
Diamond = "♦"
Heart = "♥"
Spade = "♠"

This class has two parent classes. Each of the four values of the Suit class is both a string as well as an Enum instance. Each string value is only a single Unicode character. The enumerated values must be qualified by the class name, assuring that there will be no collisions with other objects.

Here's one of the enumerated constants built by this class:

>>> Suit.Club
<Suit.Club: '♣'>

The representation of an Enum instance shows the name within the Enum class, as well as the value assigned by the other parent class. To see only the value, use an expression such as Suit.Heart.value.

We can now create cards, as shown in the following code snippet:

cards = [AceCard('A', Suit.Spade), Card('2', Suit.Spade), FaceCard('Q', Suit.Spade),]

For an example this small, this class isn't a huge improvement on single character suit codes. It is very handy to have the explicit enumeration of the domain of values. An expression such as list(Suit) will provide all of the available objects.

We do have to acknowledge that these objects aren't technically immutable. It's possible to assign additional attributes to the Suit objects. While additional attributes can be added, the value attribute cannot be changed. The following example shows the exception raised:

>>> Suit.Heart.value = 'H'
Traceback (most recent call last):
File "<doctest __main__.__test__.test_suit_value[1]>", line 1, in <module>
Suit.Heart.value = 'H'
File "/Users/slott/miniconda3/envs/py37/lib/python3.7/types.py", line 175, in __set__
raise AttributeError("can't set attribute")
AttributeError: can't set attribute
The irrelevance of immutability
Immutability can become an attractive nuisance. It's sometimes justified by a mythical malicious programmer who modifies the constant value in their application. As a design consideration, this is often silly. A mythical malicious programmer can't be stopped by creating immutable objects. A malicious programmer would have access to the Python source and be able to tweak it just as easily as they could write poorly-crafted code to modify a constant.

In Chapter 4, Attribute Access, Properties, and Descriptors, we'll show you some ways to provide suitable diagnostic information for a buggy program that's attempting to mutate objects intended to be immutable.

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

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