PEP 663: Improving Enum str(), repr(), and format()
This commit is contained in:
parent
977f1fe68a
commit
fb51d37aab
|
@ -0,0 +1,182 @@
|
|||
PEP: 663
|
||||
Title: Improving and Standardizing Enum str(), repr(), and format() behaviors
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Ethan Furman <ethan@stoneleaf.us>
|
||||
Discussions-To: python-dev@python.org
|
||||
Status: Draft
|
||||
Type: Informational
|
||||
Content-Type: text/x-rst
|
||||
Created: 23-Feb-2013
|
||||
Python-Version: 3.10
|
||||
Post-History:
|
||||
Resolution:
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
Now that we have a few years experience with Enum usage it is time to update
|
||||
the ``repr()``, ``str()``, and ``format()`` of the various enumerations by their
|
||||
intended purpose.
|
||||
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
Having the ``str()`` of ``IntEnum`` and ``IntFlag`` not be the value causes
|
||||
bugs and extra work to get the correct behavior.
|
||||
|
||||
Having the ``str()`` and ``format()`` of an enum member be different can be
|
||||
confusing.
|
||||
|
||||
The ``repr()` of ``Flag`` is not elegant.
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Enums are becoming more common in the standard library; being able to recognize
|
||||
enum members by their ``repr()``, and having that ``repr()`` be easy to parse, is
|
||||
useful and can save time and effort in understanding and debugging code.
|
||||
|
||||
However, the enums with mixed-in data types (``IntEnum``, ``StrEnum``, and
|
||||
``IntFlag``) need to be more backwards compatible with the constants they are
|
||||
replacing -- specifically, ``str(replacement_enum_member) == str(original_constant)``
|
||||
should be true (and the same for ``format()``).
|
||||
|
||||
IntEnum, IntFlag, and StrEnum should be as close to a drop-in replacement of
|
||||
existing integer and string constants as is possible. Towards that goal, the
|
||||
str() output of each should be its inherent value; i.e.::
|
||||
|
||||
>>> Color.RED
|
||||
<Color.RED: 1>
|
||||
>>> str(Color.RED)
|
||||
1
|
||||
>>> format(Color.RED>
|
||||
'1'
|
||||
|
||||
Note that format() already produces the correct output, only str() needs
|
||||
updating.
|
||||
|
||||
As much as possible, the ``str()`, ``repr()``, and ``format()`` of enum members
|
||||
should be standardized across the stardard library.
|
||||
|
||||
The repr() of Flag is... not elegant, and can be greatly improved.
|
||||
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
There a three broad categories of enum usage:
|
||||
|
||||
- standard: Enum or Flag
|
||||
a new enum class is created, and the members are used as ``class.member_name``
|
||||
|
||||
- drop-in replacement: IntEnum, IntFlag, StrEnum
|
||||
a new enum class is created which also subclasses ``int`` or ``str`` and uses
|
||||
``int.__str__`` or ``str.__str__``; the ``repr`` can be changed by using the
|
||||
``global_enum`` decorator
|
||||
|
||||
- user-mixed enums and flags
|
||||
the user creates their own integer-, float-, str-, whatever-enums instead of
|
||||
using enum.IntEnum, etc.
|
||||
|
||||
Some sample enums::
|
||||
|
||||
# module: tools.py
|
||||
|
||||
class Hue(Enum): # or IntEnum
|
||||
LIGHT = -1
|
||||
NORMAL = 0
|
||||
DARK = +1
|
||||
|
||||
class Color(Flag): # or IntFlag
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 4
|
||||
|
||||
class Grey(int, Enum): # or (int, Flag)
|
||||
BLACK = 0
|
||||
WHITE = 1
|
||||
|
||||
Using the above enumerations, the following table shows the old and new
|
||||
behavior, while the last shows the final result:
|
||||
|
||||
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| type | enum repr() | enum str() | enum format() | flag repr() | flag str() | flag format() |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| standard | 3.9 | | | | <Color.RED|GREEN: 3> | Color.RED|GREEN | Color.RED|GREEN |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | | | | <Color(3): RED|GREEN> | Color.RED|Color.GREEN | Color.RED|Color.GREEN |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| user mixed | 3.9 | | | 1 | <Grey.WHITE: 1> | | 1 |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | | | Grey.WHITE | <Grey(1): WHITE> | | Grey.WHITE |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| int drop-in | 3.9 | | Hue.LIGHT | | <Color.RED|GREEN: 3> | Color.RED|GREEN | |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | | -1 | | <Color(3): RED|GREEN> | 3 | |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| global | 3.9 | <Hue.LIGHT: -1> | Hue.LIGHT | Hue.LIGHT | <Color.RED|GREEN: 3> | Color.RED|GREEN | Color.RED|GREEN |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | tools.LIGHT | LIGHT | LIGHT | tools.RED|tools.GREEN | RED|GREEN | RED|GREEN |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| user mixed | 3.9 | <Grey.WHITE: 1 | Grey.WHITE | Grey.WHITE | <Grey.WHITE: 1> | Grey.WHITE | 1 |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | tools.WHITE | WHITE | WHITE | tools.WHITE | WHITE | WHITE |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| int drop-in | 3.9 | <Hue.LIGHT: -1> | Hue.LIGHT | | <Color.RED|GREEN: 3> | Color.RED|GREEN | |
|
||||
| +----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| | new | tools.LIGHT | -1 | | tools.RED|tools.GREEN | 3 | |
|
||||
+-------------+----------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
|
||||
Which will result in:
|
||||
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| type | enum repr() | enum str() | enum format() | flag repr() | flag str() | flag format() |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| standard | <Hue.LIGHT: -1> | Hue.LIGHT | Hue.LIGHT | <Color(3): RED|GREEN> | Color.RED|Color.GREEN | Color.RED|Color.GREEN |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| user mixed | <Grey.WHITE: 1> | Grey.WHITE | Grey.WHITE | <Grey(1): WHITE> | Grey.WHITE | Grey.WHITE |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| int drop-in | <Hue.LIGHT: -1> | -1 | -1 | <Color(3): RED|GREEN> | 3 | 3 |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| global | tools.LIGHT | LIGHT | LIGHT | tools.RED|tools.GREEN | RED|GREEN | RED|GREEN |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| user mixed | tools.WHITE | WHITE | WHITE | tools.WHITE | WHITE | WHITE |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
| int drop-in | tools.LIGHT | -1 | -1 | tools.RED|tools.GREEN | 3 | 3 |
|
||||
+-------------+-----------------+------------+-----------------------+-----------------------+------------------------+-----------------------+
|
||||
|
||||
As you can see, ``repr()`` is primarily affected by whether the members are
|
||||
global, while ``str()`` is affected by being global or by being a drop-in
|
||||
replacement, with the drop-in replacement status having a higher priority.
|
||||
Also, the basic ``repr()`` and ``str()`` have changed for flags as the old
|
||||
style was very clunky.
|
||||
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
My understanding is that ``str()`` and ``repr()`` output has much lower
|
||||
backwards compatibility requirements. Even so, I expect the majority of
|
||||
breakage to be in doc and unit tests. I'm less clear on the policy for
|
||||
``format()``.
|
||||
|
||||
Note that by changing the ``str()`` of the drop-in category, we will actually
|
||||
prevent future breakage when ``IntEnum``, et al, are used to replace existing
|
||||
constants.
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document is placed in the public domain or under the
|
||||
CC0-1.0-Universal license, whichever is more permissive.
|
Loading…
Reference in New Issue