mirror of https://github.com/python/cpython
gh-99304: [Enum] clarify what constitutes a flag alias (GH-99395)
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
parent
504e12272b
commit
73a921b070
|
@ -173,6 +173,7 @@ yourself some work and use :func:`auto()` for the values::
|
||||||
... FRIDAY = auto()
|
... FRIDAY = auto()
|
||||||
... SATURDAY = auto()
|
... SATURDAY = auto()
|
||||||
... SUNDAY = auto()
|
... SUNDAY = auto()
|
||||||
|
... WEEKEND = SATURDAY | SUNDAY
|
||||||
|
|
||||||
|
|
||||||
.. _enum-advanced-tutorial:
|
.. _enum-advanced-tutorial:
|
||||||
|
@ -305,6 +306,10 @@ Iterating over the members of an enum does not provide the aliases::
|
||||||
|
|
||||||
>>> list(Shape)
|
>>> list(Shape)
|
||||||
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
|
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
|
||||||
|
>>> list(Weekday)
|
||||||
|
[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>, <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
|
||||||
|
|
||||||
|
Note that the aliases ``Shape.ALIAS_FOR_SQUARE`` and ``Weekday.WEEKEND`` aren't shown.
|
||||||
|
|
||||||
The special attribute ``__members__`` is a read-only ordered mapping of names
|
The special attribute ``__members__`` is a read-only ordered mapping of names
|
||||||
to members. It includes all names defined in the enumeration, including the
|
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::
|
||||||
>>> [name for name, member in Shape.__members__.items() if member.name != name]
|
>>> [name for name, member in Shape.__members__.items() if member.name != name]
|
||||||
['ALIAS_FOR_SQUARE']
|
['ALIAS_FOR_SQUARE']
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Aliases for flags include values with multiple flags set, such as ``3``,
|
||||||
|
and no flags set, i.e. ``0``.
|
||||||
|
|
||||||
|
|
||||||
Comparisons
|
Comparisons
|
||||||
-----------
|
-----------
|
||||||
|
@ -751,7 +761,7 @@ flags being set, the boolean evaluation is :data:`False`::
|
||||||
False
|
False
|
||||||
|
|
||||||
Individual flags should have values that are powers of two (1, 2, 4, 8, ...),
|
Individual flags should have values that are powers of two (1, 2, 4, 8, ...),
|
||||||
while combinations of flags won't::
|
while combinations of flags will not::
|
||||||
|
|
||||||
>>> class Color(Flag):
|
>>> class Color(Flag):
|
||||||
... RED = auto()
|
... RED = auto()
|
||||||
|
@ -1096,8 +1106,8 @@ example of when ``KEEP`` is needed).
|
||||||
|
|
||||||
.. _enum-class-differences:
|
.. _enum-class-differences:
|
||||||
|
|
||||||
How are Enums different?
|
How are Enums and Flags different?
|
||||||
------------------------
|
----------------------------------
|
||||||
|
|
||||||
Enums have a custom metaclass that affects many aspects of both derived :class:`Enum`
|
Enums have a custom metaclass that affects many aspects of both derived :class:`Enum`
|
||||||
classes and their instances (members).
|
classes and their instances (members).
|
||||||
|
@ -1114,6 +1124,13 @@ responsible for ensuring that various other methods on the final :class:`Enum`
|
||||||
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
|
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
|
||||||
:meth:`__str__` and :meth:`__repr__`).
|
:meth:`__str__` and :meth:`__repr__`).
|
||||||
|
|
||||||
|
Flag Classes
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Flags 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. So, in addition to the
|
||||||
|
:class:`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.
|
||||||
|
|
||||||
Enum Members (aka instances)
|
Enum Members (aka instances)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -1123,9 +1140,35 @@ The most interesting thing about enum members is that they are singletons.
|
||||||
and then puts a custom :meth:`__new__` in place to ensure that no new ones are
|
and then puts a custom :meth:`__new__` in place to ensure that no new ones are
|
||||||
ever instantiated by returning only the existing member instances.
|
ever instantiated by returning only the existing member instances.
|
||||||
|
|
||||||
|
Flag Members
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Flag members can be iterated over just like the :class:`Flag` class, and only the
|
||||||
|
canonical members will be returned. For example::
|
||||||
|
|
||||||
|
>>> list(Color)
|
||||||
|
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
|
||||||
|
|
||||||
|
(Note that ``BLACK``, ``PURPLE``, and ``WHITE`` do not show up.)
|
||||||
|
|
||||||
|
Inverting a flag member returns the corresponding positive value,
|
||||||
|
rather than a negative value --- for example::
|
||||||
|
|
||||||
|
>>> ~Color.RED
|
||||||
|
<Color.GREEN|BLUE: 6>
|
||||||
|
|
||||||
|
Flag members have a length corresponding to the number of power-of-two values
|
||||||
|
they contain. For example::
|
||||||
|
|
||||||
|
>>> len(Color.PURPLE)
|
||||||
|
2
|
||||||
|
|
||||||
|
|
||||||
.. _enum-cookbook:
|
.. _enum-cookbook:
|
||||||
|
|
||||||
|
Enum Cookbook
|
||||||
|
-------------
|
||||||
|
|
||||||
|
|
||||||
While :class:`Enum`, :class:`IntEnum`, :class:`StrEnum`, :class:`Flag`, and
|
While :class:`Enum`, :class:`IntEnum`, :class:`StrEnum`, :class:`Flag`, and
|
||||||
:class:`IntFlag` are expected to cover the majority of use-cases, they cannot
|
:class:`IntFlag` are expected to cover the majority of use-cases, they cannot
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
An enumeration:
|
An enumeration:
|
||||||
|
|
||||||
* is a set of symbolic names (members) bound to unique values
|
* is a set of symbolic names (members) bound to unique values
|
||||||
* can be iterated over to return its members in definition order
|
* can be iterated over to return its canonical (i.e. non-alias) members in
|
||||||
|
definition order
|
||||||
* uses *call* syntax to return members by value
|
* uses *call* syntax to return members by value
|
||||||
* uses *index* syntax to return members by name
|
* uses *index* syntax to return members by name
|
||||||
|
|
||||||
|
@ -425,19 +426,23 @@ Data Types
|
||||||
in most of the same places that a string can be used. The result of any string
|
in most of the same places that a string can be used. The result of any string
|
||||||
operation performed on or with a *StrEnum* member is not part of the enumeration.
|
operation performed on or with a *StrEnum* member is not part of the enumeration.
|
||||||
|
|
||||||
.. note:: There are places in the stdlib that check for an exact :class:`str`
|
.. note::
|
||||||
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
|
|
||||||
instead of ``isinstance(unknown, str)``), and in those locations you
|
There are places in the stdlib that check for an exact :class:`str`
|
||||||
will need to use ``str(StrEnum.member)``.
|
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
|
||||||
|
instead of ``isinstance(unknown, str)``), and in those locations you
|
||||||
|
will need to use ``str(StrEnum.member)``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Using :class:`auto` with :class:`StrEnum` results in the lower-cased member
|
Using :class:`auto` with :class:`StrEnum` results in the lower-cased member
|
||||||
name as the value.
|
name as the value.
|
||||||
|
|
||||||
.. note:: :meth:`__str__` is :func:`str.__str__` to better support the
|
.. note::
|
||||||
*replacement of existing constants* use-case. :meth:`__format__` is likewise
|
|
||||||
:func:`str.__format__` for that same reason.
|
:meth:`~object.__str__` is :meth:`!str.__str__` to better support the
|
||||||
|
*replacement of existing constants* use-case. :meth:`~object.__format__` is likewise
|
||||||
|
:meth:`!str.__format__` for that same reason.
|
||||||
|
|
||||||
.. versionadded:: 3.11
|
.. versionadded:: 3.11
|
||||||
|
|
||||||
|
@ -469,13 +474,17 @@ Data Types
|
||||||
|
|
||||||
.. method:: __iter__(self):
|
.. method:: __iter__(self):
|
||||||
|
|
||||||
Returns all contained members::
|
Returns all contained non-alias members::
|
||||||
|
|
||||||
>>> list(Color.RED)
|
>>> list(Color.RED)
|
||||||
[<Color.RED: 1>]
|
[<Color.RED: 1>]
|
||||||
>>> list(purple)
|
>>> list(purple)
|
||||||
[<Color.RED: 1>, <Color.BLUE: 4>]
|
[<Color.RED: 1>, <Color.BLUE: 4>]
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
|
||||||
|
Aliases are no longer returned during iteration.
|
||||||
|
|
||||||
.. method:: __len__(self):
|
.. method:: __len__(self):
|
||||||
|
|
||||||
Returns number of members in flag::
|
Returns number of members in flag::
|
||||||
|
@ -585,9 +594,15 @@ Data Types
|
||||||
Using :class:`auto` with :class:`IntFlag` results in integers that are powers
|
Using :class:`auto` with :class:`IntFlag` results in integers that are powers
|
||||||
of two, starting with ``1``.
|
of two, starting with ``1``.
|
||||||
|
|
||||||
.. versionchanged:: 3.11 :meth:`__str__` is now :func:`int.__str__` to
|
.. versionchanged:: 3.11
|
||||||
better support the *replacement of existing constants* use-case.
|
|
||||||
:meth:`__format__` was already :func:`int.__format__` for that same reason.
|
:meth:`~object.__str__` is now :meth:`!int.__str__` to better support the
|
||||||
|
*replacement of existing constants* use-case. :meth:`~object.__format__` was
|
||||||
|
already :meth:`!int.__format__` for that same reason.
|
||||||
|
|
||||||
|
Inversion of a :class:`!IntFlag` now returns a positive value that is the
|
||||||
|
union of all flags not in the given flag, rather than a negative value.
|
||||||
|
This matches the existing :class:`Flag` behavior.
|
||||||
|
|
||||||
.. class:: ReprEnum
|
.. class:: ReprEnum
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue