Hearts, Spades, Diamonds, Clubs
Enumerated types are a common tool in programming languages:
enum
module added to Python standard library in version 3.4
Here's how to use it:
from enum import Enum
class A(Enum):
X = 1
Y = 2
Z = 3
Access members as usual:
A.X
A.X == 1
A.X == A.X
A.Y == A.X
a = A.X
b = A.X
a is b
Values may be looked up by "name" using [ ]
notation
key = "Y"
...
A[key]
Enums have dict-like access!
A[key] is A.Y
Also supports "backwards" lookup via ( )
:
A(1)
(note: this would usually be creating a new object of type A
)
Bidirectional mapping between a name (string) and some value!
A.W # AttributeError
A['W'] # KeyError
A[1] # KeyError
A(9) # ValueError
Enums are iterable over all values (order is preserved)
list(A)
B = Enum("B", "X Y Z")
B.X
B(3)
B = Enum("B", [('X', 90), ('Y', 45)])
B.X
# Values can be mixed types
class B(Enum):
X = 1
Y = "some string."
Z = 0.3
L = [] # note the list!
B("some string.")
B([])
B(0.3)
BTW, you should NOT use floating points to do indexing
key = 0.1 + 0.2
B(key) # B(0.3)
# Cannot reassign values
B.X = 2
B.L.append(1)
We will have to start thinking differently.....
class A(Enum):
X = 1
Y = 2
Z = 3
A.X
isinstance(A.X, int)
isinstance(A.X, A)
type(A.X)
When creating the class:
One little "goof":
A.X.X.Y
^ Because instances of objects have access to members of their class, all enums have each-other as attributes (Don't use this!)
So where are 1, 2, 3
in A?
A.X.value
A.X.name
The value
& name
attributes are *the* important things to know about python Enums
B.L
B.L.value.append(7)
B.L
So they are semi-immutable (like tuples)
class A(Enum):
X = 1
Y = 2
def add_ten(self):
return self.value + 10
list(A)
add_ten
not included as enum member -- behaves as typical python method
A.add_ten
A.X.add_ten()
class C(Enum):
X = 1
Y = lambda a: print('Y(a=%r)' % a)
list(C)
C.X.Y()
So lambdas are interpreted as methods (as usual)
Can I get a little crazy now?
class A(Enum):
class J:
def __init__(self):
print("constructing J")
class M:
def __init__(self):
print("constructing M")
list(A)
m = A.M.value()
type(m)
class A(Enum):
class J:
def __init__(self):
print("constructing J")
class M:
def __init__(self):
print("constructing M")
def New(self):
return self.value()
@classmethod
def From(cls, foo):
return cls[foo.upper()].New()
classname = 'J'
A[classname].New()
A.From('m')
Back to basics...
class A(Enum):
X = 1
Y = 2
# TypeError: Cannot extend enumerations
class B(A):
Z = 3
[(a.name, a.value) for a in A]
B = Enum("B", [(a.name, a.value) for a in A] + [('Z', 3)])
list(B)
int()
compatibleint
, so comparisons works.value
from enum import IntEnum
class A(IntEnum):
X = 1
Y = 2
A.X
A.X == 1
class B(IntEnum):
X = 1
Y = '2'
B.Y == 2
B('2')
&
, |
operations to combine enumerated valuesfrom enum import Flag, IntFlag
class A(Flag):
X = 1 # 1 << 0
Y = 2 # 1 << 1
Z = 4 # 1 << 2
a = A.X | A.Z
a
isinstance(a, A)
a & A.X
a & A.Y
a & A.Z
auto-enumeration works as expected
A = IntFlag("A", "W X Y Z")
list(A)
A(13)
<A.Z|Y|W: 13>
for a in A:
print(f'{a.name} = 0b{a:05b}')
When you have finite set of things and want name & value lookup + iteration for free
Examples:
class Suit(Enum):
Hearts = 1
Clubs = 2
Spades = 3
Diamonds = 4
def is_red(self):
return self in (Suit.Hearts, Suit.Diamonds)
list(Suit)
Suit.Diamonds.is_red()
from itertools import product
deck = list(product(Suit, range(1, 14)))
deck[:5]
from random import shuffle
shuffle(deck)
deck[:6]
class Card:
def __init__(self, suit, face):
if isinstance(suit, str):
suit = Suit[suit]
self.suit = suit
self.face = face
def __repr__(self):
if 1 < self.face < 11:
f = self.face
else:
f = self.FaceToLetter(self.face).name
return "<Card %s %s>" % (f, self.suit.name)
class FaceToLetter(Enum):
A = 1
J = 11
Q = 12
K = 13
from itertools import starmap
deck = list(starmap(Card, product(Suit, range(1, 14))))
deck[::5]
class Perm(IntFlag):
READ = 1
WRITE = 2
EXEC = 4
def __str__(self):
return (('r' if self & self.READ else '-') +
('w' if self & self.WRITE else '-') +
('x' if self & self.EXEC else '-'))
'%s' % (Perm.READ | Perm.EXEC)
'r-x'
Perm(6)
<Perm.EXEC|WRITE: 6>
user
, group
, all
.class UnixPermission:
def __init__(self, user: Perm, group: Perm, all: Perm):
self.user = user
self.group = group
self.all = all
@classmethod
def from_int(cls, num):
return cls(Perm((num >> 6) & 7),
Perm((num >> 3) & 7),
Perm((num >> 0) & 7))
def __str__(self):
return '%s%s%s' % (self.user, self.group, self.all)
str(UnixPermission.from_int(0o755))
'rwxr-xr-x'
Famous Status Codes: * 200 - OK * 404 - Not Found * 500 - Internal Server Error
HttpMethod = Enum("HttpMethod", "GET POST PUT DELETE")
try:
method = HttpMethod[method_str]
except KeyError:
raise UnknownHttpMethodException(method_str)
class HttpStatus(IntEnum):
OK = 200
NOT_FOUND = 404
INTERNAL_SERVER_ERROR = 500
class HttpError(Exception):
pass
class HttpErrorNotFound(HttpError):
status = HttpStatus.NOT_FOUND
class HttpErrorISE(HttpError):
status = HttpStatus.INTERNAL_SERVER_ERROR
from http import HTTPStatus
HTTPStatus
HTTPStatus['OK']
HTTPStatus["OK"].description
HTTPStatus(404)
list(HTTPStatus)