Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 663 – 标准化 Enum 的 str()、repr() 和 format() 行为

作者:
Ethan Furman <ethan at stoneleaf.us>
讨论列表:
Python-Dev 列表
状态:
已拒绝
类型:
信息性
创建日期:
2021年6月30日
Python 版本:
3.11
历史记录:
2021年7月20日,2021年11月2日
决议:
Python-Dev 消息

目录

摘要

更新各种 Enum 类型的 repr()str()format() 以更好地匹配其预期用途。例如,IntEnumstr() 将更改为与其 format() 匹配,而用户混合的 int-enum 的 format() 将与其 str() 匹配。在所有情况下,枚举的 str()format() 将相同(除非用户覆盖 format())。

添加一个全局枚举装饰器,该装饰器将装饰的枚举的 str()repr()(以及 format())更改为有效的全局引用:即 re.IGNORECASE 而不是 <RegexFlag.IGNORECASE: 2>

动机

IntEnumIntFlagstr() 不是值会导致错误,并在替换现有常量时增加额外的工作。

枚举成员的 str()format() 不同可能会令人困惑。

添加 StrEnum 及其要求 str() 为其 value 与其他提供的 Enum 的 str 不一致。

Flag 成员的迭代,这直接影响其 repr(),充其量是不优雅的,最坏的情况是存在错误。

基本原理

枚举在标准库中变得越来越普遍;能够通过其 repr() 识别枚举成员,并使该 repr() 易于解析,这很有用,并且可以节省理解和调试代码的时间和精力。

但是,混合数据类型的枚举(IntEnumIntFlag 和新的 StrEnum)需要与它们替换的常量具有更好的向后兼容性——具体来说,str(replacement_enum_member) == str(original_constant) 应为真(format() 也一样)。

IntEnum、IntFlag 和 StrEnum 应尽可能接近现有整数和字符串常量的直接替换。为了达到这个目标,每个枚举的 str() 输出应为其固有值;例如,如果 Color 是一个 IntEnum

>>> Color.RED
<Color.RED: 1>
>>> str(Color.RED)
'1'
>>> format(Color.RED)
'1'

请注意,format() 已经产生了正确的输出,只需要更新 str()

尽可能地,枚举成员的 str()repr()format() 应该在标准库中标准化。但是,在 Python 3.10 之前,标准库中的几个枚举具有自定义的 str() 和/或 repr()

Flagrepr() 目前包含别名,它不应该包含;修复这一点当然会在某些情况下更改其 repr()

规范

枚举的使用主要有三种类别

  • 简单:EnumFlag 创建一个没有数据类型混合的新枚举类
  • 直接替换:IntEnumIntFlagStrEnum 创建一个新的枚举类,它也继承自 intstr 并使用 int.__str__str.__str__
  • 用户混合的枚举和标志用户创建自己的整数、浮点数、字符串或其他类型的枚举,而不是使用 enum.IntEnum 等。

还有两种风格

  • 普通:枚举成员保留在其类中,并作为 classname.membername 访问,并且类名显示在其 repr()str() 中(在适当的情况下)
  • 全局:枚举成员被复制到其模块的全局命名空间中,并且它们的模块名称显示在其 repr()str() 中(在适当的情况下)

一些示例枚举

# 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

使用上述枚举,下表显示了旧输出和新输出(空白单元格表示没有更改)

风格 类别 枚举 repr() 枚举 str() 枚举 format()
普通 简单 3.10
用户混合 3.10 1
Grey.WHITE
int 直接替换 3.10 Hue.LIGHT
-1
全局 简单 3.10 <Hue.LIGHT: -1> Hue.LIGHT Hue.LIGHT
tools.LIGHT LIGHT LIGHT
用户混合 3.10 <Grey.WHITE: 1 Grey.WHITE Grey.WHITE
tools.WHITE WHITE WHITE
int 直接替换 3.10 <Hue.LIGHT: -1> Hue.LIGHT
tools.LIGHT -1
风格 类别 标志 repr() 标志 str() 标志 format()
普通 简单 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN Color.RED|GREEN
<Color(3): RED|GREEN> Color.RED|Color.GREEN Color.RED|Color.GREEN
用户混合 3.10 <Grey.WHITE: 1> 1
<Grey(1): WHITE> Grey.WHITE
int 直接替换 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN
<Color(3): RED|GREEN> 3
全局 简单 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN Color.RED|GREEN
tools.RED|tools.GREEN RED|GREEN RED|GREEN
用户混合 3.10 <Grey.WHITE: 1> Grey.WHITE 1
tools.WHITE WHITE WHITE
int 直接替换 3.10 <Color.RED|GREEN: 3> Color.RED|GREEN
tools.RED|tools.GREEN 3

这两个表格显示了最终结果

风格 类别 枚举 repr() 枚举 str() 枚举 format()
普通 简单 <Hue.LIGHT: -1> Hue.LIGHT Hue.LIGHT
用户混合 <Grey.WHITE: 1> Grey.WHITE Grey.WHITE
int 直接替换 <Hue.LIGHT: -1> -1 -1
全局 简单 tools.LIGHT LIGHT LIGHT
用户混合 tools.WHITE WHITE WHITE
int 直接替换 tools.LIGHT -1 -1
风格 类别 标志 repr() 标志 str() 标志 format()
普通 简单 <Color(3): RED|GREEN> Color.RED|Color.GREEN Color.RED|Color.GREEN
用户混合 <Grey(1): WHITE> Grey.WHITE Grey.WHITE
int 直接替换 <Color(3): RED|GREEN> 3 3
全局 简单 tools.RED|tools.GREEN RED|GREEN RED|GREEN
用户混合 tools.WHITE WHITE WHITE
int 直接替换 tools.RED|tools.GREEN 3 3

可以看出,repr() 主要受成员是否为全局的影响,而 str() 受是否为全局或直接替换的影响,其中直接替换的状态优先级更高。此外,标志的基本 repr()str() 已更改,因为旧样式存在缺陷。

向后兼容性

字符串化对象的向后兼容性在主要 Python 版本之间没有保证,并且在软件使用枚举的 repr()str()format() 输出进行测试、文档、数据结构和/或代码生成时,将出现向后兼容性中断。

枚举成员的正常使用不会改变:re.ASCII 仍然可以作为 re.ASCII 使用,并且仍然与 256 相等。

如果需要维护以前的输出,例如为了确保不同 Python 版本之间的兼容性,软件项目将需要创建自己的枚举基类,并覆盖相应的自定义方法。

请注意,通过更改直接替换类别的 str(),我们实际上可以防止将来在使用 IntEnum 等替换现有常量时出现中断。


来源:https://github.com/python/peps/blob/main/peps/pep-0663.rst

上次修改时间:2023年9月9日 17:39:29 GMT