Changeset 9262fe9

Mar 4, 2024, 6:09:26 PM (7 weeks ago)
Peter A. Buhr <pabuhr@…>

more proofreading for enumeration related-work

1 edited


  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r647e2ea r9262fe9  
    4 Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}, and algebraic data-types in functional programming.
     4In general, an \Newterm{algebraic data type} (ADT) is a composite type, \ie, a type formed by combining other types.
     5Three common classes of algebraic types are \Newterm{array type}, \ie homogeneous types, \Newterm{product type}, \ie heterogeneous tuples and records (structures), and \Newterm{sum type}, \ie tagged product-types (unions).
     6Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization.
     7Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
     9Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, Haskell~\cite{Haskell} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
    510Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
    714718Via mem::discriminant
    716 mem::discriminant returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
    717 Casting
     720@mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
    719724If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
     1194An @Enum@ is a set of symbolic names bound to unique values.
     1195They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features.
     1197They are most useful when you have a variable that can take one of a limited selection of values. For example, the days of the week:
     1199>>> from enum import Enum
     1200>>> class Weekday(Enum):
     1201...    MONDAY = 1
     1202...    TUESDAY = 2
     1203...    WEDNESDAY = 3
     1204...    THURSDAY = 4
     1205...    FRIDAY = 5
     1206...    SATURDAY = 6
     1207...    SUNDAY = 7
     1209Or perhaps the RGB primary colors:
     1211>>> from enum import Enum
     1212>>> class Color(Enum):
     1213...    RED = 1
     1214...    GREEN = 2
     1215...    BLUE = 3
     1217As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself.
     1219Note: Case of Enum Members
     1221Because Enums are used to represent constants, and to help avoid issues with name clashes between mixin-class methods/attributes and enum names, we strongly recommend using @UPPER_CASE@ names for members, and will be using that style in our examples.
     1223Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
     1225>>> Weekday(3)
     1226<Weekday.WEDNESDAY: 3>
     1228As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
     1229The @str()@ of a member shows only the enum name and member name:
     1234The type of an enumeration member is the enum it belongs to:
     1236>>> type(Weekday.MONDAY)
     1237<enum 'Weekday'>
     1238isinstance(Weekday.FRIDAY, Weekday)
     1241Enum members have an attribute that contains just their name:
     1243>>> print(
     1246Likewise, they have an attribute for their value:
     1248>>> Weekday.WEDNESDAY.value
     1251Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
     1252For example, has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
     1253The difference is that one of them counts from 0-6 and the other from 1-7.
     1254Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
     1257def from_date(cls, date):
     1258    return cls(date.isoweekday())
     1260The complete Weekday enum now looks like this:
     1262>>> class Weekday(Enum):
     1263...    MONDAY = 1
     1264...    TUESDAY = 2
     1265...    WEDNESDAY = 3
     1266...    THURSDAY = 4
     1267...    FRIDAY = 5
     1268...    SATURDAY = 6
     1269...    SUNDAY = 7
     1270...    #
     1271...    $@$classmethod
     1272...    def from_date(cls, date):
     1273...        return cls(date.isoweekday())
     1275Now we can find out what today is! Observe:
     1277>>> from datetime import date
     1278>>> Weekday.from_date(     
     1279<Weekday.TUESDAY: 2>
     1281Of course, if you're reading this on some other day, you'll see that day instead.
     1283This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
     1285>>> from enum import Flag
     1286>>> class Weekday(Flag):
     1287...    MONDAY = 1
     1288...    TUESDAY = 2
     1289...    WEDNESDAY = 4
     1290...    THURSDAY = 8
     1291...    FRIDAY = 16
     1292...    SATURDAY = 32
     1293...    SUNDAY = 64
     1295We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
     1297Just like the original @Weekday@ enum above, we can have a single selection:
     1299>>> first_week_day = Weekday.MONDAY
     1300>>> first_week_day
     1301<Weekday.MONDAY: 1>
     1303But @Flag@ also allows us to combine several members into a single variable:
     1305>>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
     1306>>> weekend
     1307<Weekday.SATURDAY|SUNDAY: 96>
     1309You can even iterate over a @Flag@ variable:
     1311>>> for day in weekend:
     1312...    print(day)
     1316Okay, let's get some chores set up:
     1318>>> chores_for_ethan = {
     1319...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
     1320...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
     1321...    'answer SO questions': Weekday.SATURDAY,
     1322...    }
     1324And a function to display the chores for a given day:
     1326>>> def show_chores(chores, day):
     1327...    for chore, days in chores.items():
     1328...        if day in days:
     1329...            print(chore)
     1330>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
     1331answer SO questions
     1333In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
     1335>>> from enum import auto
     1336>>> class Weekday(Flag):
     1337...    MONDAY = auto()
     1338...    TUESDAY = auto()
     1339...    WEDNESDAY = auto()
     1340...    THURSDAY = auto()
     1341...    FRIDAY = auto()
     1342...    SATURDAY = auto()
     1343...    SUNDAY = auto()
     1344...    WEEKEND = SATURDAY | SUNDAY
     1347\subsection{Programmatic access to enumeration members and their attributes}
     1349Sometimes it's useful to access members in enumerations programmatically (i.e. situations where @Color.RED@ won't do because the exact color is not known at program-writing time).
     1350@Enum@ allows such access:
     1352>>> Color(1)
     1353<Color.RED: 1>
     1354>>> Color(3)
     1355<Color.BLUE: 3>
     1357If you want to access enum members by name, use item access:
     1360<Color.RED: 1>
     1363<Color.GREEN: 2>
     1365If you have an enum member and need its name or value:
     1367>>> member = Color.RED
     1370>>> member.value
     1374\subsection{Duplicating enum members and values}
     1376Having two enum members with the same name is invalid:
     1378>>> class Shape(Enum):
     1379...    SQUARE = 2
     1380...    SQUARE = 3
     1382Traceback (most recent call last):
     1384TypeError: 'SQUARE' already defined as 2
     1386However, an enum member can have other names associated with it.
     1387Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
     1388By-value lookup of the value of @A@ will return the member @A@.
     1389By-name lookup of @A@ will return the member @A@.
     1390By-name lookup of @B@ will also return the member @A@:
     1392>>> class Shape(Enum):
     1393...    SQUARE = 2
     1394...    DIAMOND = 1
     1395...    CIRCLE = 3
     1396...    ALIAS_FOR_SQUARE = 2
     1398>>> Shape.SQUARE
     1399<Shape.SQUARE: 2>
     1400>>> Shape.ALIAS_FOR_SQUARE
     1401<Shape.SQUARE: 2>
     1402>>> Shape(2)
     1403<Shape.SQUARE: 2>
     1406Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
     1408\subsection{Ensuring unique enumeration values}
     1410By default, enumerations allow multiple names as aliases for the same value.
     1411When this behavior isn't desired, you can use the @unique()@ decorator:
     1413>>> from enum import Enum, unique
     1414>>> $@$unique
     1415... class Mistake(Enum):
     1416...     ONE = 1
     1417...     TWO = 2
     1418...     THREE = 3
     1419...     FOUR = 3
     1421Traceback (most recent call last):
     1423ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
     1426\subsection{Using automatic values}
     1428If the exact value is unimportant you can use @auto@:
     1430>>> from enum import Enum, auto
     1431>>> class Color(Enum):
     1432...     RED = auto()
     1433...     BLUE = auto()
     1434...     GREEN = auto()
     1436>>> [member.value for member in Color]
     1437[1, 2, 3]
     1439The values are chosen by \_generate\_next\_value\_(), which can be overridden:
     1441>>> class AutoName(Enum):
     1442...     $@$staticmethod
     1443...     def _generate_next_value_(name, start, count, last_values):
     1444...         return name
     1446>>> class Ordinal(AutoName):
     1447...     NORTH = auto()
     1448...     SOUTH = auto()
     1449...     EAST = auto()
     1450...     WEST = auto()
     1452>>> [member.value for member in Ordinal]
     1453['NORTH', 'SOUTH', 'EAST', 'WEST']
     1455Note The @_generate_next_value_()@ method must be defined before any members.
     1459Iterating over the members of an enum does not provide the aliases:
     1461>>> list(Shape)
     1462[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
     1463>>> list(Weekday)
     1464[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
     1465<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
     1467Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
     1469The special attribute @__members__@ is a read-only ordered mapping of names to members.
     1470It includes all names defined in the enumeration, including the aliases:
     1472>>> for name, member in Shape.__members__.items():
     1473...     name, member
     1475('SQUARE', <Shape.SQUARE: 2>)
     1476('DIAMOND', <Shape.DIAMOND: 1>)
     1477('CIRCLE', <Shape.CIRCLE: 3>)
     1478('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
     1480The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
     1481For example, finding all the aliases:
     1483>>> [name for name, member in Shape.__members__.items() if != name]
     1486Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
     1490Enumeration members are compared by identity:
     1492>>> Color.RED is Color.RED
     1494>>> Color.RED is Color.BLUE
     1496>>> Color.RED is not Color.BLUE
     1499Ordered comparisons between enumeration values are not supported.
     1500Enum members are not integers (but see @IntEnum@ below):
     1502>>> Color.RED < Color.BLUE
     1503Traceback (most recent call last):
     1504  File "<stdin>", line 1, in <module>
     1505TypeError: '<' not supported between instances of 'Color' and 'Color'
     1507Equality comparisons are defined though:
     1509>>> Color.BLUE == Color.RED
     1511>>> Color.BLUE != Color.RED
     1513>>> Color.BLUE == Color.BLUE
     1516Comparisons against non-enumeration values will always compare not equal (again, @IntEnum@ was explicitly designed to behave differently, see below):
     1518>>> Color.BLUE == 2
     1522Warning: It is possible to reload modules -- if a reloaded module contains enums, they will be recreated, and the new members may not compare identical/equal to the original members.
     1524\subsection{Allowed members and attributes of enumerations}
     1526Most of the examples above use integers for enumeration values.
     1527Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
     1528In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
     1529But if the value is important, enumerations can have arbitrary values.
     1531Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:
     1533>>> class Mood(Enum):
     1534...     FUNKY = 1
     1535...     HAPPY = 3
     1537...     def describe(self):
     1538...         # self is the member here
     1539...         return, self.value
     1541...     def __str__(self):
     1542...         return 'my custom str! {0}'.format(self.value)
     1544...     $@$classmethod
     1546...     def favorite_mood(cls):
     1547...         # cls here is the enumeration
     1548...         return cls.HAPPY
     1553>>> Mood.favorite_mood()
     1554<Mood.HAPPY: 3>
     1555>>> Mood.HAPPY.describe()
     1556('HAPPY', 3)
     1557>>> str(Mood.FUNKY)
     1558'my custom str! 1'
     1560The rules for what is allowed are as follows: names that start and end with a single underscore are reserved by enum and cannot be used;
     1561all other attributes defined within an enumeration will become members of this enumeration, with the exception of special methods (@__str__()@, @__add__()@, etc.), descriptors (methods are also descriptors), and variable names listed in @_ignore_@.
     1563Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
     1564See Planet for an example.
     1566Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
     1567it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
     1568See When to use @__new__()@ vs. @__init__()@ for more details.
     1570\subsection{Restricted Enum subclassing}
     1572A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
     1573The order of these base classes is:
     1575class EnumName([mix-in, ...,] [data-type,] base-enum):
     1576    pass
     1578Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
     1579So this is forbidden:
     1581>>> class MoreColor(Color):
     1582...     PINK = 17
     1584Traceback (most recent call last):
     1586TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
     1588But this is allowed:
     1590>>> class Foo(Enum):
     1591...     def some_behavior(self):
     1592...         pass
     1594>>> class Bar(Foo):
     1595...     HAPPY = 1
     1596...     SAD = 2
     1599Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
     1600On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)
     1602\subsection{Dataclass support}
     1604When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
     1605For example:
     1607>>> from dataclasses import dataclass, field
     1608>>> $@$dataclass
     1609... class CreatureDataMixin:
     1610...     size: str
     1611...     legs: int
     1612...     tail: bool = field(repr=False, default=True)
     1614>>> class Creature(CreatureDataMixin, Enum):
     1615...     BEETLE = 'small', 6
     1616...     DOG = 'medium', 4
     1618>>> Creature.DOG
     1619<Creature.DOG: size='medium', legs=4>
     1621Use the @dataclass()@ argument repr=False to use the standard @repr()@.
     1623Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
     1627Enumerations can be pickled and unpickled:
     1629>>> from test.test_enum import Fruit
     1630>>> from pickle import dumps, loads
     1631>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
     1634The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.
     1636Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
     1638It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
     1639The default method is by-value, but enums with complicated values may want to use by-name:
     1641>>> import enum
     1642>>> class MyEnum(enum.Enum):
     1643...     __reduce_ex__ = enum.pickle_by_enum_name
     1645Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
     1647\subsection{Functional API}
     1649The @Enum@ class is callable, providing the following functional API:
     1651>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
     1652>>> Animal
     1653<enum 'Animal'>
     1654>>> Animal.ANT
     1655<Animal.ANT: 1>
     1656>>> list(Animal)
     1657[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
     1659The semantics of this API resemble @namedtuple@.
     1660The first argument of the call to @Enum@ is the name of the enumeration.
     1662The second argument is the source of enumeration member names.
     1663It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values.
     1664The last two options enable assigning arbitrary values to enumerations;
     1665the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
     1666A new class derived from @Enum@ is returned.
     1667In other words, the above assignment to Animal is equivalent to:
     1669>>> class Animal(Enum):
     1670...     ANT = 1
     1671...     BEE = 2
     1672...     CAT = 3
     1673...     DOG = 4
     1676The reason for defaulting to 1 as the starting number and not 0 is that 0 is @False@ in a boolean sense, but by default enum members all evaluate to @True@.
     1678Pickling enums created with the functional API can be tricky as frame stack implementation details are used to try and figure out which module the enumeration is being created in (e.g. it will fail if you use a utility function in a separate module, and also may not work on IronPython or Jython).
     1679The solution is to specify the module name explicitly as follows:
     1681>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
     1683Warning: If module is not supplied, and @Enum@ cannot determine what it is, the new @Enum@ members will not be unpicklable; to keep errors closer to the source, pickling will be disabled.
     1685The new pickle protocol 4 also, in some circumstances, relies on @__qualname__@ being set to the location where pickle will be able to find the class.
     1686For example, if the class was made available in class SomeData in the global scope:
     1688>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
     1690The complete signature is:
     1693    value='NewEnumName',
     1694    names=<...>,
     1695    *,
     1696    module='...',
     1697    qualname='...',
     1698    type=<mixed-in class>,
     1699    start=1,
     1700    )
     1704@value@: What the new enum class will record as its name.
     1706@names@: The enum members.
     1707This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):
     1711or an iterator of names:
     1713['RED', 'GREEN', 'BLUE']
     1715or an iterator of (name, value) pairs:
     1717[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
     1719or a mapping:
     1721{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
     1724module: name of module where new enum class can be found.
     1726@qualname@: where in module new enum class can be found.
     1728@type@: type to mix in to new enum class.
     1730@start@: number to start counting at if only names are passed in.
     1732Changed in version 3.5: The start parameter was added.
     1734\subsection{Derived Enumerations}
     1738The first variation of @Enum@ that is provided is also a subclass of @int@.
     1739Members of an @IntEnum@ can be compared to integers;
     1740by extension, integer enumerations of different types can also be compared to each other:
     1742>>> from enum import IntEnum
     1743>>> class Shape(IntEnum):
     1744...     CIRCLE = 1
     1745...     SQUARE = 2
     1747>>> class Request(IntEnum):
     1748...     POST = 1
     1749...     GET = 2
     1751>>> Shape == 1
     1753>>> Shape.CIRCLE == 1
     1755>>> Shape.CIRCLE == Request.POST
     1758However, they still can't be compared to standard @Enum@ enumerations:
     1760>>> class Shape(IntEnum):
     1761...     CIRCLE = 1
     1762...     SQUARE = 2
     1764>>> class Color(Enum):
     1765...     RED = 1
     1766...     GREEN = 2
     1768>>> Shape.CIRCLE == Color.RED
     1771@IntEnum@ values behave like integers in other ways you'd expect:
     1773>>> int(Shape.CIRCLE)
     1775>>> ['a', 'b', 'c'][Shape.CIRCLE]
     1777>>> [i for i in range(Shape.SQUARE)]
     1778[0, 1]
     1783The second variation of @Enum@ that is provided is also a subclass of @str@.
     1784Members of a @StrEnum@ can be compared to strings;
     1785by extension, string enumerations of different types can also be compared to each other.
     1787New in version 3.11.
     1791The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
     1792The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
     1793Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
     1795Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
     1797Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
     1798See @FlagBoundary@ for details.
     1800New in version 3.6.
     1802Changed in version 3.11.
     1804Sample @IntFlag@ class:
     1806>>> from enum import IntFlag
     1807>>> class Perm(IntFlag):
     1808...     R = 4
     1809...     W = 2
     1810...     X = 1
     1812>>> Perm.R | Perm.W
     1813<Perm.R|W: 6>
     1814>>> Perm.R + Perm.W
     1816>>> RW = Perm.R | Perm.W
     1817>>> Perm.R in RW
     1820It is also possible to name the combinations:
     1822>>> class Perm(IntFlag):
     1823...     R = 4
     1824...     W = 2
     1825...     X = 1
     1826...     RWX = 7
     1828>>> Perm.RWX
     1829<Perm.RWX: 7>
     1830>>> ~Perm.RWX
     1831<Perm: 0>
     1832>>> Perm(7)
     1833<Perm.RWX: 7>
     1835Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
     1837Changed in version 3.11.
     1839Another important difference between @IntFlag@ and @Enum@ is that if no flags are set (the value is 0), its boolean evaluation is @False@:
     1841>>> Perm.R & Perm.X
     1842<Perm: 0>
     1843>>> bool(Perm.R & Perm.X)
     1846Because @IntFlag@ members are also subclasses of int they can be combined with them (but may lose @IntFlag@ membership:
     1848>>> Perm.X | 4
     1849<Perm.R|X: 5>
     1851>>> Perm.X + 8
     1854Note: The negation operator, @~@, always returns an @IntFlag@ member with a positive value:
     1856>>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
     1859@IntFlag@ members can also be iterated over:
     1861>>> list(RW)
     1862[<Perm.R: 4>, <Perm.W: 2>]
     1864New in version 3.11.
     1868The last variation is @Flag@.
     1869Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
     1870Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
     1871While it is possible to specify the values directly it is recommended to use @auto@ as the value and let @Flag@ select an appropriate value.
     1873New in version 3.6.
     1875Like @IntFlag@, if a combination of @Flag@ members results in no flags being set, the boolean evaluation is @False@:
     1877>>> from enum import Flag, auto
     1878>>> class Color(Flag):
     1879...     RED = auto()
     1880...     BLUE = auto()
     1881...     GREEN = auto()
     1883>>> Color.RED & Color.GREEN
     1884<Color: 0>
     1885>>> bool(Color.RED & Color.GREEN)
     1888Individual flags should have values that are powers of two (1, 2, 4, 8, ...), while combinations of flags will not:
     1890>>> class Color(Flag):
     1891...     RED = auto()
     1892...     BLUE = auto()
     1893...     GREEN = auto()
     1894...     WHITE = RED | BLUE | GREEN
     1896>>> Color.WHITE
     1897<Color.WHITE: 7>
     1899Giving a name to the ``no flags set'' condition does not change its boolean value:
     1901>>> class Color(Flag):
     1902...     BLACK = 0
     1903...     RED = auto()
     1904...     BLUE = auto()
     1905...     GREEN = auto()
     1907>>> Color.BLACK
     1908<Color.BLACK: 0>
     1909>>> bool(Color.BLACK)
     1912@Flag@ members can also be iterated over:
     1914>>> purple = Color.RED | Color.BLUE
     1915>>> list(purple)
     1916[<Color.RED: 1>, <Color.BLUE: 2>]
     1918New in version 3.11.
     1920Note: For the majority of new code, @Enum@ and @Flag@ are strongly recommended, since @IntEnum@ and @IntFlag@ break some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations).
     1921@IntEnum@ and @IntFlag@ should be used only in cases where @Enum@ and @Flag@ will not do;
     1922for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
     1926While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
     1928class IntEnum(int, Enum):
     1929    pass
     1931This demonstrates how similar derived enumerations can be defined;
     1932for example a @FloatEnum@ that mixes in float instead of @int@.
     1934Some rules:
     1937When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
     1939Mix-in types must be subclassable.
     1940For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
     1942While @Enum@ can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. @int@ above.
     1943This restriction does not apply to mix-ins which only add methods and don't specify another type.
     1945When another data type is mixed in, the value attribute is not the same as the enum member itself, although it is equivalent and will compare equal.
     1947A data type is a mixin that defines @__new__()@, or a @dataclass@
     1949\%-style formatting: @%s@ and @%r@ call the @Enum@ class's @__str__()@ and @__repr__()@ respectively; other codes (such as @%i@ or @%h@ for @IntEnum@) treat the enum member as its mixed-in type.
     1951Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
     1953Note: Because @IntEnum@, @IntFlag@, and @StrEnum@ are designed to be drop-in replacements for existing constants, their @__str__()@ method has been reset to their data types' @__str__()@ method.
     1955\subsection{When to use \lstinline{__new__()} vs. \lstinline{__init__()}}
     1957@__new__()@ must be used whenever you want to customize the actual value of the @Enum@ member.
     1958Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
     1960For example, if you want to pass several items to the constructor, but only want one of them to be the value:
     1962>>> class Coordinate(bytes, Enum):
     1963...     """
     1964...     Coordinate with binary codes that can be indexed by the int code.
     1965...     """
     1966...     def __new__(cls, value, label, unit):
     1967...         obj = bytes.__new__(cls, [value])
     1968...         obj._value_ = value
     1969...         obj.label = label
     1970...         obj.unit = unit
     1971...         return obj
     1972...     PX = (0, 'P.X', 'km')
     1973...     PY = (1, 'P.Y', 'km')
     1974...     VX = (2, 'V.X', 'km/s')
     1975...     VY = (3, 'V.Y', 'km/s')
     1977>>> print(Coordinate['PY'])
     1980>>> print(Coordinate(3))
     1983Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found; instead, use the data type directly.
     1985\subsection{Finer Points}
     1987Supported @__dunder__@ names
     1989@__members__@ is a read-only ordered mapping of member\_name:member items. It is only available on the class.
     1991@__new__()@, if specified, must create and return the enum members; it is also a very good idea to set the member's @_value_@ appropriately. Once all the members are created it is no longer used.
     1992Supported @_sunder_@ names
     1995@_name_@ -- name of the member
     1997@_value_@ -- value of the member; can be set / modified in @__new__@
     1999@_missing_@ -- a lookup function used when a value is not found; may be overridden
     2001@_ignore_@ -- a list of names, either as a @list@ or a @str@, that will not be transformed into members, and will be removed from the final class
     2003@_order_@ -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)
     2005@_generate_@next@_value_@ -- used by the Functional API and by @auto@ to get an appropriate value for an enum member; may be overridden
     2007Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
     2009For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
     2011New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
     2013New in version 3.7: @_ignore_@
     2015To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
     2016It will be checked against the actual order of the enumeration and raise an error if the two do not match:
     2018>>> class Color(Enum):
     2019...     _order_ = 'RED GREEN BLUE'
     2020...     RED = 1
     2021...     BLUE = 3
     2022...     GREEN = 2
     2024Traceback (most recent call last):
     2026TypeError: member order does not match _order_:
     2027  ['RED', 'BLUE', 'GREEN']
     2028  ['RED', 'GREEN', 'BLUE']
     2030Note: In Python 2 code the @_order_@ attribute is necessary as definition order is lost before it can be recorded.
     2034Private names are not converted to enum members, but remain normal attributes.
     2036Changed in version 3.11.
     2038\subsection{\lstinline{Enum} member type}
     2040@Enum@ members are instances of their enum class, and are normally accessed as @EnumClass.member@.
     2041In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
     2042however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
     2044Changed in version 3.5.
     2046\subsection{Creating members that are mixed with other data types}
     2048When subclassing other data types, such as @int@ or @str@, with an @Enum@, all values after the = @are@ passed to that data type's constructor. For example:
     2050>>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer
     2051...     example = '11', 16      # so x='11' and base=16
     2053MyEnum.example.value        # and hex(11) is...
     2057\subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
     2059Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
     2060otherwise, all members evaluate as @True@.
     2061To make your own enum's boolean evaluation depend on the member's value add the following to your class:
     2063def __bool__(self):
     2064    return bool(self.value)
     2066Plain @Enum@ classes always evaluate as @True@.
     2068\subsection{\lstinline{Enum} classes with methods}
     2070If you give your enum subclass extra methods, like the Planet class below, those methods will show up in a dir() of the member, but not of the class:
     2072>>> dir(Planet)                         
     2074 '__class__', '__doc__', '__members__', '__module__']
     2075>>> dir(Planet.EARTH)                   
     2076['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
     2079\subsection{Combining members of \lstinline{Flag}}
     2081Iterating over a combination of @Flag@ members will only return the members that are comprised of a single bit:
     2083>>> class Color(Flag):
     2084...     RED = auto()
     2085...     GREEN = auto()
     2086...     BLUE = auto()
     2087...     MAGENTA = RED | BLUE
     2088...     YELLOW = RED | GREEN
     2089...     CYAN = GREEN | BLUE
     2091>>> Color(3)  # named combination
     2092<Color.YELLOW: 3>
     2093>>> Color(7)      # not named combination
     2094<Color.RED|GREEN|BLUE: 7>
     2097\subsection{\lstinline{Flag} and \lstinline{IntFlag} minutia}
     2099Using the following snippet for our examples:
     2101>>> class Color(IntFlag):
     2102...     BLACK = 0
     2103...     RED = 1
     2104...     GREEN = 2
     2105...     BLUE = 4
     2106...     PURPLE = RED | BLUE
     2107...     WHITE = RED | GREEN | BLUE
     2110the following are true:
     2113single-bit flags are canonical
     2115multi-bit and zero-bit flags are aliases
     2117only canonical flags are returned during iteration:
     2119>>> list(Color.WHITE)
     2120[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
     2122negating a flag or flag set returns a new flag/flag set with the corresponding positive integer value:
     2124>>> Color.BLUE
     2125<Color.BLUE: 4>
     2127>>> ~Color.BLUE
     2128<Color.RED|GREEN: 3>
     2131names of pseudo-flags are constructed from their members' names:
     2133>>> (Color.RED | Color.GREEN).name
     2137multi-bit flags, aka aliases, can be returned from operations:
     2139>>> Color.RED | Color.BLUE
     2140<Color.PURPLE: 5>
     2142>>> Color(7)  # or Color(-1)
     2143<Color.WHITE: 7>
     2145>>> Color(0)
     2146<Color.BLACK: 0>
     2149membership / containment checking: zero-valued flags are always considered to be contained:
     2151>>> Color.BLACK in Color.WHITE
     2154otherwise, only if all bits of one flag are in the other flag will True be returned:
     2156>>> Color.PURPLE in Color.WHITE
     2159>>> Color.GREEN in Color.PURPLE
     2163There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: @STRICT@, @CONFORM@, @EJECT@, and @KEEP@:
     2166@STRICT@ --> raises an exception when presented with invalid values
     2168@CONFORM@ --> discards any invalid bits
     2170@EJECT@ --> lose Flag status and become a normal int with the given value
     2172@KEEP@ --> keep the extra bits
     2175keeps Flag status and extra bits
     2177extra bits do not show up in iteration
     2179extra bits do show up in repr() and str()
     2182The default for @Flag@ is @STRICT@, the default for @IntFlag@ is @EJECT@, and the default for @_convert_@ is @KEEP@ (see @ssl.Options@ for an example of when @KEEP@ is needed).
     2184\section{How are Enums and Flags different?}
     2186Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
     2188\subsection{Enum Classes}
     2190The @EnumType@ metaclass is responsible for providing the @__contains__()@, @__dir__()@, @__iter__()@ and other methods that allow one to do things with an @Enum@ class that fail on a typical class, such as @list(Color)@ or @some_enum_var@ in @Color@.
     2191@EnumType@ is responsible for ensuring that various other methods on the final @Enum@ class are correct (such as @__new__()@, @__getnewargs__()@, @__str__()@ and @__repr__()@).
     2193\subsection{Flag Classes}
     2195Flags have an expanded view of aliasing: to be canonical, the value of a flag needs to be a power-of-two value, and not a duplicate name.
     2196So, in addition to the @Enum@ definition of alias, a flag with no value (a.k.a. 0) or with more than one power-of-two value (e.g. 3) is considered an alias.
     2198\subsection{Enum Members (aka instances)}
     2200The most interesting thing about enum members is that they are singletons.
     2201@EnumType@ creates them all while it is creating the enum class itself, and then puts a custom @__new__()@ in place to ensure that no new ones are ever instantiated by returning only the existing member instances.
     2203\subsection{Flag Members}
     2205Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
     2206For example:
     2208>>> list(Color)
     2209[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
     2211(Note that BLACK, PURPLE, and WHITE do not show up.)
     2213Inverting a flag member returns the corresponding positive value, rather than a negative value -- for example:
     2215>>> ~Color.RED
     2216<Color.GREEN|BLUE: 6>
     2218Flag members have a length corresponding to the number of power-of-two values they contain. For example:
     2220>>> len(Color.PURPLE)
     2224\subsection{Enum Cookbook}
     2226While @Enum@, @IntEnum@, @StrEnum@, @Flag@, and @IntFlag@ are expected to cover the majority of use-cases, they cannot cover them all. Here are recipes for some different types of enumerations that can be used directly, or as examples for creating one's own.
     2228\subsection{Omitting values}
     2230In many use-cases, one doesn't care what the actual value of an enumeration is. There are several ways to define this type of simple enumeration:
     2233use instances of auto for the value
     2235use instances of object as the value
     2237use a descriptive string as the value
     2239use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
     2241Using any of these methods signifies to the user that these values are not important, and also enables one to add, remove, or reorder members without having to renumber the remaining members.
     2243\subsection{Using \lstinline{auto}}
     2245Using @auto@ would look like:
     2247>>> class Color(Enum):
     2248...     RED = auto()
     2249...     BLUE = auto()
     2250...     GREEN = auto()
     2252>>> Color.GREEN
     2253<Color.GREEN: 3>
     2256\subsection{Using \lstinline{object}}
     2258Using @object@ would look like:
     2260>>> class Color(Enum):
     2261...     RED = object()
     2262...     GREEN = object()
     2263...     BLUE = object()
     2265>>> Color.GREEN                         
     2266<Color.GREEN: <object object at 0x...>>
     2268This is also a good example of why you might want to write your own @__repr__()@:
     2270>>> class Color(Enum):
     2271...     RED = object()
     2272...     GREEN = object()
     2273...     BLUE = object()
     2274...     def __repr__(self):
     2275...         return "<%s.%s>" % (self.__class__.__name__, self._name_)
     2277>>> Color.GREEN
     2281\subsection{Using a descriptive string}
     2283Using a string as the value would look like:
     2285>>> class Color(Enum):
     2286...     RED = 'stop'
     2287...     GREEN = 'go'
     2288...     BLUE = 'too fast!'
     2290>>> Color.GREEN
     2291<Color.GREEN: 'go'>
     2294\subsection{Using a custom \lstinline{__new__()}}
     2296Using an auto-numbering @__new__()@ would look like:
     2298>>> class AutoNumber(Enum):
     2299...     def __new__(cls):
     2300...         value = len(cls.__members__) + 1
     2301...         obj = object.__new__(cls)
     2302...         obj._value_ = value
     2303...         return obj
     2305>>> class Color(AutoNumber):
     2306...     RED = ()
     2307...     GREEN = ()
     2308...     BLUE = ()
     2310>>> Color.GREEN
     2311<Color.GREEN: 2>
     2313To make a more general purpose @AutoNumber@, add @*args@ to the signature:
     2315>>> class AutoNumber(Enum):
     2316...     def __new__(cls, *args):      # this is the only change from above
     2317...         value = len(cls.__members__) + 1
     2318...         obj = object.__new__(cls)
     2319...         obj._value_ = value
     2320...         return obj
     2322Then when you inherit from @AutoNumber@ you can write your own @__init__@ to handle any extra arguments:
     2324>>> class Swatch(AutoNumber):
     2325...     def __init__(self, pantone='unknown'):
     2326...         self.pantone = pantone
     2327...     AUBURN = '3497'
     2328...     SEA_GREEN = '1246'
     2329...     BLEACHED_CORAL = () # New color, no Pantone code yet!
     2331>>> Swatch.SEA_GREEN
     2332<Swatch.SEA_GREEN: 2>
     2333>>> Swatch.SEA_GREEN.pantone
     2335>>> Swatch.BLEACHED_CORAL.pantone
     2338Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
     2339it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
     2341Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
     2342instead, use the data type directly -- e.g.:
     2344obj = int.__new__(cls, value)
     2349An ordered enumeration that is not based on @IntEnum@ and so maintains the normal @Enum@ invariants (such as not being comparable to other enumerations):
     2351>>> class OrderedEnum(Enum):
     2352...     def __ge__(self, other):
     2353...         if self.__class__ is other.__class__:
     2354...             return self.value >= other.value
     2355...         return NotImplemented
     2356...     def __gt__(self, other):
     2357...         if self.__class__ is other.__class__:
     2358...             return self.value > other.value
     2359...         return NotImplemented
     2360...     def __le__(self, other):
     2361...         if self.__class__ is other.__class__:
     2362...             return self.value <= other.value
     2363...         return NotImplemented
     2364...     def __lt__(self, other):
     2365...         if self.__class__ is other.__class__:
     2366...             return self.value < other.value
     2367...         return NotImplemented
     2369>>> class Grade(OrderedEnum):
     2370...     A = 5
     2371...     B = 4
     2372...     C = 3
     2373...     D = 2
     2374...     F = 1
     2375>>> Grade.C < Grade.A
     2381Raises an error if a duplicate member value is found instead of creating an alias:
     2383>>> class DuplicateFreeEnum(Enum):
     2384...     def __init__(self, *args):
     2385...         cls = self.__class__
     2386...         if any(self.value == e.value for e in cls):
     2387...             a =
     2388...             e = cls(self.value).name
     2389...             raise ValueError(
     2390...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
     2391...                 % (a, e))
     2392>>> class Color(DuplicateFreeEnum):
     2393...     RED = 1
     2394...     GREEN = 2
     2395...     BLUE = 3
     2396...     GRENE = 2
     2398Traceback (most recent call last):
     2399  ...
     2400ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
     2402Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
     2403If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
     2407If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
     2409>>> class Planet(Enum):
     2410...     MERCURY = (3.303e+23, 2.4397e6)
     2411...     VENUS   = (4.869e+24, 6.0518e6)
     2412...     EARTH   = (5.976e+24, 6.37814e6)
     2413...     MARS    = (6.421e+23, 3.3972e6)
     2414...     JUPITER = (1.9e+27,   7.1492e7)
     2415...     SATURN  = (5.688e+26, 6.0268e7)
     2416...     URANUS  = (8.686e+25, 2.5559e7)
     2417...     NEPTUNE = (1.024e+26, 2.4746e7)
     2418...     def __init__(self, mass, radius):
     2419...         self.mass = mass       # in kilograms
     2420...         self.radius = radius   # in meters
     2421...     $\@$property
     2422...     def surface_gravity(self):
     2423...         # universal gravitational constant  (m3 kg-1 s-2)
     2424...         G = 6.67300E-11
     2425...         return G * self.mass / (self.radius * self.radius)
     2427>>> Planet.EARTH.value
     2428(5.976e+24, 6378140.0)
     2429>>> Planet.EARTH.surface_gravity
     2435An example to show the @_ignore_@ attribute in use:
     2437>>> from datetime import timedelta
     2438>>> class Period(timedelta, Enum):
     2439...     "different lengths of time"
     2440...     _ignore_ = 'Period i'
     2441...     Period = vars()
     2442...     for i in range(367):
     2443...         Period['day_%d' % i] = i
     2445>>> list(Period)[:2]
     2446[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
     2447>>> list(Period)[-2:]
     2448[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
     2451\subsection{Subclassing EnumType}
     2453While most enum needs can be met by customizing @Enum@ subclasses, either with class decorators or custom functions, @EnumType@ can be subclassed to provide a different Enum experience.
    11882456\section{Algebraic Data Type}
Note: See TracChangeset for help on using the changeset viewer.