Skip to content

Commit 73a921b

Browse files
gh-99304: [Enum] clarify what constitutes a flag alias (GH-99395)
Co-authored-by: C.A.M. Gerlach <[email protected]>
1 parent 504e122 commit 73a921b

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

Doc/howto/enum.rst

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ yourself some work and use :func:`auto()` for the values::
173173
... FRIDAY = auto()
174174
... SATURDAY = auto()
175175
... SUNDAY = auto()
176+
... WEEKEND = SATURDAY | SUNDAY
176177

177178

178179
.. _enum-advanced-tutorial:
@@ -305,6 +306,10 @@ Iterating over the members of an enum does not provide the aliases::
305306

306307
>>> list(Shape)
307308
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
309+
>>> list(Weekday)
310+
[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>, <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
311+
312+
Note that the aliases ``Shape.ALIAS_FOR_SQUARE`` and ``Weekday.WEEKEND`` aren't shown.
308313

309314
The special attribute ``__members__`` is a read-only ordered mapping of names
310315
to members. It includes all names defined in the enumeration, including the
@@ -324,6 +329,11 @@ the enumeration members. For example, finding all the aliases::
324329
>>> [name for name, member in Shape.__members__.items() if member.name != name]
325330
['ALIAS_FOR_SQUARE']
326331

332+
.. note::
333+
334+
Aliases for flags include values with multiple flags set, such as ``3``,
335+
and no flags set, i.e. ``0``.
336+
327337

328338
Comparisons
329339
-----------
@@ -751,7 +761,7 @@ flags being set, the boolean evaluation is :data:`False`::
751761
False
752762

753763
Individual flags should have values that are powers of two (1, 2, 4, 8, ...),
754-
while combinations of flags won't::
764+
while combinations of flags will not::
755765

756766
>>> class Color(Flag):
757767
... RED = auto()
@@ -1096,8 +1106,8 @@ example of when ``KEEP`` is needed).
10961106

10971107
.. _enum-class-differences:
10981108

1099-
How are Enums different?
1100-
------------------------
1109+
How are Enums and Flags different?
1110+
----------------------------------
11011111

11021112
Enums have a custom metaclass that affects many aspects of both derived :class:`Enum`
11031113
classes and their instances (members).
@@ -1114,6 +1124,13 @@ responsible for ensuring that various other methods on the final :class:`Enum`
11141124
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
11151125
:meth:`__str__` and :meth:`__repr__`).
11161126

1127+
Flag Classes
1128+
^^^^^^^^^^^^
1129+
1130+
Flags have an expanded view of aliasing: to be canonical, the value of a flag
1131+
needs to be a power-of-two value, and not a duplicate name. So, in addition to the
1132+
:class:`Enum` definition of alias, a flag with no value (a.k.a. ``0``) or with more than one
1133+
power-of-two value (e.g. ``3``) is considered an alias.
11171134

11181135
Enum Members (aka instances)
11191136
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1123,9 +1140,35 @@ The most interesting thing about enum members is that they are singletons.
11231140
and then puts a custom :meth:`__new__` in place to ensure that no new ones are
11241141
ever instantiated by returning only the existing member instances.
11251142

1143+
Flag Members
1144+
^^^^^^^^^^^^
1145+
1146+
Flag members can be iterated over just like the :class:`Flag` class, and only the
1147+
canonical members will be returned. For example::
1148+
1149+
>>> list(Color)
1150+
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
1151+
1152+
(Note that ``BLACK``, ``PURPLE``, and ``WHITE`` do not show up.)
1153+
1154+
Inverting a flag member returns the corresponding positive value,
1155+
rather than a negative value --- for example::
1156+
1157+
>>> ~Color.RED
1158+
<Color.GREEN|BLUE: 6>
1159+
1160+
Flag members have a length corresponding to the number of power-of-two values
1161+
they contain. For example::
1162+
1163+
>>> len(Color.PURPLE)
1164+
2
1165+
11261166

11271167
.. _enum-cookbook:
11281168

1169+
Enum Cookbook
1170+
-------------
1171+
11291172

11301173
While :class:`Enum`, :class:`IntEnum`, :class:`StrEnum`, :class:`Flag`, and
11311174
:class:`IntFlag` are expected to cover the majority of use-cases, they cannot

Doc/library/enum.rst

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
An enumeration:
2828

2929
* is a set of symbolic names (members) bound to unique values
30-
* can be iterated over to return its members in definition order
30+
* can be iterated over to return its canonical (i.e. non-alias) members in
31+
definition order
3132
* uses *call* syntax to return members by value
3233
* uses *index* syntax to return members by name
3334

@@ -425,19 +426,23 @@ Data Types
425426
in most of the same places that a string can be used. The result of any string
426427
operation performed on or with a *StrEnum* member is not part of the enumeration.
427428

428-
.. note:: There are places in the stdlib that check for an exact :class:`str`
429-
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
430-
instead of ``isinstance(unknown, str)``), and in those locations you
431-
will need to use ``str(StrEnum.member)``.
429+
.. note::
430+
431+
There are places in the stdlib that check for an exact :class:`str`
432+
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
433+
instead of ``isinstance(unknown, str)``), and in those locations you
434+
will need to use ``str(StrEnum.member)``.
432435

433436
.. note::
434437

435438
Using :class:`auto` with :class:`StrEnum` results in the lower-cased member
436439
name as the value.
437440

438-
.. note:: :meth:`__str__` is :func:`str.__str__` to better support the
439-
*replacement of existing constants* use-case. :meth:`__format__` is likewise
440-
:func:`str.__format__` for that same reason.
441+
.. note::
442+
443+
:meth:`~object.__str__` is :meth:`!str.__str__` to better support the
444+
*replacement of existing constants* use-case. :meth:`~object.__format__` is likewise
445+
:meth:`!str.__format__` for that same reason.
441446

442447
.. versionadded:: 3.11
443448

@@ -469,13 +474,17 @@ Data Types
469474

470475
.. method:: __iter__(self):
471476

472-
Returns all contained members::
477+
Returns all contained non-alias members::
473478

474479
>>> list(Color.RED)
475480
[<Color.RED: 1>]
476481
>>> list(purple)
477482
[<Color.RED: 1>, <Color.BLUE: 4>]
478483

484+
.. versionchanged:: 3.11
485+
486+
Aliases are no longer returned during iteration.
487+
479488
.. method:: __len__(self):
480489

481490
Returns number of members in flag::
@@ -585,9 +594,15 @@ Data Types
585594
Using :class:`auto` with :class:`IntFlag` results in integers that are powers
586595
of two, starting with ``1``.
587596

588-
.. versionchanged:: 3.11 :meth:`__str__` is now :func:`int.__str__` to
589-
better support the *replacement of existing constants* use-case.
590-
:meth:`__format__` was already :func:`int.__format__` for that same reason.
597+
.. versionchanged:: 3.11
598+
599+
:meth:`~object.__str__` is now :meth:`!int.__str__` to better support the
600+
*replacement of existing constants* use-case. :meth:`~object.__format__` was
601+
already :meth:`!int.__format__` for that same reason.
602+
603+
Inversion of a :class:`!IntFlag` now returns a positive value that is the
604+
union of all flags not in the given flag, rather than a negative value.
605+
This matches the existing :class:`Flag` behavior.
591606

592607
.. class:: ReprEnum
593608

0 commit comments

Comments
 (0)