【问题标题】:Using objects as the values of an Enum?使用对象作为枚举的值?
【发布时间】:2022-05-11 08:29:22
【问题描述】:

我目前正在尝试创建一个基于枚举/常量的系统,用于在 Python 中定义颜色。我想避免在尝试使用/访问颜色时使用字符串。

在理想的世界里,我希望能够做到:

>>> print(Colours.BLACK)
Black

>>> print(Colours.WHITE.hex)
ffffff

到目前为止,我已经提出了一个基于枚举和对象的系统,如下所示:

from enum import Enum

class Colour:

  def __init__(self, name, hex = "000000"):
    self.name = name
    self.hex = hex

  def __str__(self):
    return self.name


class Colours(Enum):
  WHITE = Colour("White", "ffffff")
  BLACK = Colour("Black", "000000")

print(Colours.BLACK.value)

print(Colours.WHITE.value.hex)

哪个打印:

Black
ffffff

但是,将对象分配为枚举的值感觉像是一种糟糕的做法,我以前在其他地方没有见过这种做法。

这被认为是坏事吗?如果有,为什么?

还有没有更好的方法来实现我想要的结果?

编辑:

我最终采用了这种方法,按照@MichealButscher 的建议使用__hash__,并使用__str__ 和__repr__ 来避免使用.value。

from enum import Enum

class Colour:

  def __init__(self, label, hex_value = "000000"):
    self.label = label
    self.hex_value = hex

  def __str__(self):
    return self.label

  def __hash__(self):
    hash(self.label)


class Colours(Enum):
  WHITE = Colour("White", "ffffff")
  BLACK = Colour("Black", "000000")

  def __repr__(self):
    return self.value

  def __str__(self):
    return str(self.value)

【问题讨论】:

  • "Colour" 应该定义一个 __hash__ 函数来将其对象标记为不可变(文档也应该说明这一点)。那么在我看来,在枚举中使用复杂的对象是完全可以的。顺便说一下,整数也是 Python 中的对象。
  • @MichaelButscher 很好的建议,感谢您的洞察力。

标签: python enums


【解决方案1】:

一切都是对象,所以 some 对象将被分配。但是,您可以仅使用元组中的颜色名称和十六进制值作为值,并让Colour.__init__ 处理使用元组初始化每个实例。

class Colour(Enum):
    WHITE = ("White", "ffffff")
    BLACK = ("Black", "000000")

    def __init__(self, label, hexvalue):
        self.label = label
        self.hexvalue = hexvalue

(警告:某些属性名称已在使用中,不能被覆盖甚至分配给,例如,如果您尝试使用name 而不是label 和value 而不是hex value.)

【讨论】:

  • 你错了。 name 和 value没有已经在使用中,并且可以正常工作。
  • 感谢您的建议。我想我会采用我原来的解决方案,但在重命名变量时采纳你的建议。它适用于这些名称,但在访问颜色名称时可能会造成混淆(即Colours.WHITE.value.name,而Colours.WHITE.name 是其他名称)
  • @martineau:你说得对:name 和 value 可以用于成员 names,但不能用于其他成员 attributes.
  • @chepner:成员定义中不需要括号。
  • @Ethan:你错了,我们不可能都对。顺便说一句,我也认为括号很好(PEP 20:“显式优于隐式”)。
【解决方案2】:

除非您需要单独的颜色类,否则只需将其全部组合到枚举中即可:

from enum import Enum

class Colour(Enum):
    WHITE = "ffffff"
    BLACK = "000000"
    #
    def __str__(self):
        return self.name

并在使用中:

>>> Colour.WHITE
<Colour.WHITE: 'ffffff'>

>>> str(Colour.WHITE)
'WHITE'

>>> Colour.WHITE.value
'ffffff'

@martineau,@chepner 说以下将失败:

from enum import Enum

class Colour(Enum):
    WHITE = 'White', "ffffff"
    BLACK = 'black', "000000"
    #
    def __init__(self, name, hex):
        self.name = name              # uh-oh
        self.hex = hex
    #
    def __str__(self):
        return self.name

确实如此:

Traceback (most recent call last):
  ...
AttributeError: <enum 'Enum'> cannot set attribute 'name'

我认为您所说的是以下内容将起作用:

class Example(Enum):
    name = 'a name member'
    value = 'a value member'

使用中:

>>> list(Example)
[<Example.name: 'a name member'>, <Example.value: 'a value member'>]

>>> Example.name.name
'name'

如果你不这么说,那你就错了。 :-/

就 PEP 20 而言,逗号是明确的。

【讨论】:

  • 这就是我的意思。至于逗号,他们是否创建 tuple 是上下文相关的,所以我认为在回答问题时(对于可能的 Python 菜鸟)来说清楚发生了什么是好的。
  • @martineau:你可能是对的——我只是讨厌无关紧要的括号。
猜你喜欢
  • 2017-05-01
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 2021-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多