【问题标题】:Adding members to Python Enums将成员添加到 Python 枚举
【发布时间】:2015-01-24 14:06:03
【问题描述】:

我知道这不是标准用例,但我需要动态地将元素添加到 Python 中的 IntEnum 派生类。请注意,使用功能 API 动态创建 Enum 是不够的。我需要向现有枚举添加元素。我该怎么做?

背景:对于那些想知道为什么有人要这样做的人。我正在包装一个库,枚举的值是在库中定义的。我可以使用库 API 查询名称和值。但是我不能在初始化时这样做,因为它取决于库根据用户请求动态加载的组件。我可以在启动时加载所有组件并使用功能 API 在导入时创建枚举,但这很耗时并且有副作用。

【问题讨论】:

  • ENUM 的重点不就是不变性吗?
  • 你不能。甚至 扩展现有枚举的子类 也受到防范。
  • @MartijnPieters 对这个特定用例有什么建议吗?
  • @MightyPork 是的,但是 Python 是一种很棒的动态胶水语言,很多时候你需要与你无法控制的东西进行交互。
  • @Hernan:我很好奇你为什么不接受你需要的答案?

标签: python dynamic enums


【解决方案1】:

这是来自aenum library1extend_enum 函数的作业。


一对夫妇样本Enums:

from aenum import Enum

class Color(Enum):
    black = 0

class ColorHelp(Enum):
    _init_ = 'value __doc__'
    black = 0, 'the absence of color'

extend_enum 在行动:

from aenum import extend_enum

extend_enum(Color, 'white', 1)
print Color, list(Color)
print repr(Color.black), Color.black, repr(Color.white), Color.white
print

extend_enum(ColorHelp, 'white', 1, 'the presence of every color')
print ColorHelp, list(ColorHelp)
print repr(ColorHelp.black), ColorHelp.black, ColorHelp.black.__doc__, repr(ColorHelp.white), ColorHelp.white, ColorHelp.white.__doc__

这给了我们:

<enum 'Color'> [<Color.black: 0>, <Color.white: 1>]
<Color.black: 0> Color.black <Color.white: 1> Color.white

<enum 'ColorHelp'> [<ColorHelp.black: 0>, <ColorHelp.white: 1>]
<ColorHelp.black: 0> ColorHelp.black the absence of color <ColorHelp.white: (1, 'the presence of every color')> ColorHelp.white None

1 披露:我是Python stdlib Enumenum34 backportAdvanced Enumeration (aenum) 库的作者。

【讨论】:

  • 我得到“文件”/home/vamalov/.local/lib/python3.5/site-packages/aenum/__init__.py”,第2166行,在canonical_member._values_中的canonical_value的extend_enum中: AttributeError: 'MachineName' 对象没有属性 'values'",其中 MachineName 通常是 python 枚举。这个方法还能用吗?
  • @likern,如果这仍然是一个问题,请file an issue。谢谢。
  • 对于遇到与@likern 相同错误的任何人,请确保使用aenum 的Enum (from aenum import Enum) 而不是常规的Enum (from enum import Enum)。
  • 它也是可以腌制的。
  • @EthanFurman 我想更正我之前的评论。我无法加载带有扩展枚举的泡菜对象。默认枚举定义不包括某些项目。 ValueError: 不是有效的
【解决方案2】:

枚举是不可变的,这才是重点。您可以创建一个新的枚举来替换原来的枚举:

from enum import Enum

names = [m.name for m in ExistingEnum] + ['newname1', 'newname2']
ExistingEnum = Enum('ExistingEnum', names)

但任何现有的引用(例如,在其他模块中)将继续使用旧定义。

names 可以是:

  • 包含成员名称的字符串,以空格或逗号分隔。值从start 递增 1(可以设置为关键字参数,默认为 1)。
  • 一个可迭代的成员名称(如上面的代码)。值从 start 开始加 1。
  • (成员名称、值)对的可迭代。
  • 成员名称 -> 值对的映射。

【讨论】:

  • 正如我所提到的,这不是一个选项,原因与您描述的完全相同。还是谢谢
  • @Hernan:不过,这是您在使用 enum 库时的唯一选项。
  • 不变性不是枚举的“重点”。存在枚举是为了保证有限无序集上的互斥。在运行时将其他成员附加到现有枚举上绝不违反此保证。 Python 的标准 enum.Enum 类型选择禁止这种有效用例,但绝不会禁止第三方替代方案这样做。另请参阅:可变的 aenum.EnumJava enum 类型。
  • @CecilCurry:这些库都没有改变原始枚举,它们扩展了现有的枚举以创建一个新的枚举。如果枚举在运行时是可变的,那将产生广泛的影响,您不能再保证处理所有可能的值(像 Rust 这样的语言甚至在枚举不是运行时可变的情况下构建它们的类型安全)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多