Update the repr()
, str()
, and format()
of the various Enum types to better match their intended purpose. For example, IntEnum
will have its str()
change to match its format()
, while a user-mixed int-enum will have its format()
match its str()
. In all cases, an enum’s str()
and format()
will be the same (unless the user overrides format()
).
Add a global enum decorator which changes the str()
and repr()
(and format()
) of the decorated enum to be a valid global reference: i.e. re.IGNORECASE
instead of <RegexFlag.IGNORECASE: 2>
.
Having the str()
of IntEnum
and IntFlag
not be the value causes bugs and extra work when replacing existing constants.
Having the str()
and format()
of an enum member be different can be confusing.
The addition of StrEnum
with its requirement to have its str()
be its value
is inconsistent with other provided Enum’s str
.
The iteration of Flag
members, which directly affects their repr()
, is inelegant at best, and buggy at worst.
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
, IntFlag
, and the new StrEnum
) 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; e.g. if Color
is an IntEnum
:
>>> 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 standard library. However, up to Python 3.10 several enums in the standard library have a custom str()
and/or repr()
.
The repr()
of Flag currently includes aliases, which it should not; fixing that will, of course, already change its repr()
in certain cases.
There are three broad categories of enum usage:
Enum
or Flag
a new enum class is created with no data type mixinsIntEnum
, IntFlag
, StrEnum
a new enum class is created which also subclasses int
or str
and uses int.__str__
or str.__str__
There are also two styles:
classname.membername
, and the class name shows in their repr()
and str()
(where appropriate)repr()
and str()
(where appropriate)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 two tables show the old and new output (blank cells indicate no change):
style category enum repr() enum str() enum format() normal simple 3.10 new user mixed 3.10 1 new Grey.WHITE int drop-in 3.10 Hue.LIGHT new -1 global simple 3.10 <Hue.LIGHT: -1> Hue.LIGHT Hue.LIGHT new tools.LIGHT LIGHT LIGHT user mixed 3.10 <Grey.WHITE: 1 Grey.WHITE Grey.WHITE new tools.WHITE WHITE WHITE int drop-in 3.10 <Hue.LIGHT: -1> Hue.LIGHT new tools.LIGHT -1 style category flag repr() flag str() flag format() normal simple 3.10 <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.10 <Grey.WHITE: 1> 1 new <Grey(1): WHITE> Grey.WHITE int drop-in 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN new <Color(3): RED|GREEN> 3 global simple 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN Color.RED|GREEN new tools.RED|tools.GREEN RED|GREEN RED|GREEN user mixed 3.10 <Grey.WHITE: 1> Grey.WHITE 1 new tools.WHITE WHITE WHITE int drop-in 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN new tools.RED|tools.GREEN 3These two tables show the final result:
style category enum repr() enum str() enum format() normal simple <Hue.LIGHT: -1> Hue.LIGHT Hue.LIGHT user mixed <Grey.WHITE: 1> Grey.WHITE Grey.WHITE int drop-in <Hue.LIGHT: -1> -1 -1 global simple tools.LIGHT LIGHT LIGHT user mixed tools.WHITE WHITE WHITE int drop-in tools.LIGHT -1 -1 style category flag repr() flag str() flag format() normal simple <Color(3): RED|GREEN> Color.RED|Color.GREEN Color.RED|Color.GREEN user mixed <Grey(1): WHITE> Grey.WHITE Grey.WHITE int drop-in <Color(3): RED|GREEN> 3 3 global simple tools.RED|tools.GREEN RED|GREEN RED|GREEN user mixed tools.WHITE WHITE WHITE int drop-in tools.RED|tools.GREEN 3 3As can be seen, 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 flawed.
Backwards compatibility of stringified objects is not guaranteed across major Python versions, and there will be backwards compatibility breaks where software uses the repr()
, str()
, and format()
output of enums in tests, documentation, data structures, and/or code generation.
Normal usage of enum members will not change: re.ASCII
can still be used as re.ASCII
and will still compare equal to 256
.
If the previous output needs to be maintained, for example to ensure compatibility between different Python versions, software projects will need to create their own enum base class with the appropriate methods overridden.
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.
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4