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

Python 增强提案

PEP 663 – 枚举 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 消息

目录

摘要

更新各种枚举类型的 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,这与其他提供的枚举的 str 不一致。

Flag 成员的迭代,这直接影响它们的 repr(),充其量是笨拙的,最坏情况是错误的。

基本原理

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

然而,带有混合数据类型的枚举(IntEnum, IntFlag, 和新的 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 在不混合数据类型的情况下创建了一个新的枚举类
  • 直接替换:IntEnum, IntFlag, StrEnum 创建了一个新的枚举类,该类还继承自 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
整数直接替换 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
整数直接替换 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
整数直接替换 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
整数直接替换 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
整数直接替换 <Hue.LIGHT: -1> -1 -1
全局 简单 tools.LIGHT LIGHT LIGHT
用户混合 tools.WHITE WHITE WHITE
整数直接替换 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
整数直接替换 <Color(3): RED|GREEN> 3 3
全局 简单 tools.RED|tools.GREEN RED|GREEN RED|GREEN
用户混合 tools.WHITE WHITE WHITE
整数直接替换 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

最后修改:2025-02-01 08:59:27 GMT