【问题标题】:Referring Enum members to each other相互引用 Enum 成员
【发布时间】:2018-10-13 23:29:02
【问题描述】:

我在 Python 中定义了以下枚举:

class Unit(Enum):
    GRAM = ("g")
    KILOGRAM = ("kg", GRAM, 1000.0)

    def __init__(self, symbol, base_unit = None, multiplier = 1.0):
        self.symbol = symbol
        self.multiplier = multiplier
        self.base_unit = self if base_unit is None else base_unit

我希望如此

print(Unit.GRAM.base_unit)
print(Unit.KILOGRAM.base_unit)

会回来

Unit.GRAM
Unit.GRAM

然而,我得到的却很混乱

Unit.GRAM
g

为什么会这样?

【问题讨论】:

标签: python python-3.x


【解决方案1】:

Python 定义类的方式包括创建一个新的作用域、处理一堆语句(变量赋值、函数定义等),然后然后实际基于局部变量创建一个类对象在所有这些语句运行后存在。在最后一步之前,没有任何内容会转换为 Enum 实例。

你可以这样理解:

def make_class_Unit():
  GRAM = ("g")
  KILOGRAM = ("kg", GRAM, 1000.0)

  def __init__(self, symbol, base_unit = None, multiplier = 1.0):
    self.symbol = symbol
    self.multiplier = multiplier
    self.base_unit = self if base_unit is None else base_unit
  return make_class(name='Unit', base=Enum, contents=locals())

Unit = make_class_Unit()

这样看,希望你能看出在定义KILOGRAM的时候,GRAM其实只是一个字符串。它直到最后一个阶段才成为Unit 实例,在此我调用(虚构的)make_class() 函数。1


1虽然我上面使用的 make_class 函数实际上并不存在于那个名称下,但它与 Python 真正所做的并没有太大区别,即调用 type 的构造函数或一个元类(在这种情况下是Enums 的元类)。

【讨论】:

    【解决方案2】:

    DavidZ 很好地解释了这个问题。

    你需要解决这个问题的最后一点是:当每个成员的__init__被运行时,Enum已经被创建——所以你可以调用它:

    self.base_unit = self if base_unit is None else self.__class__(base_unit)
    

    【讨论】:

    • 有趣。我认为,Unit.KILOGRAM.base_unitUnit.GRAM 可能会引用不同的对象,但 id(Unit.GRAM)id(Unit.KILOGRAM.base_unit)id(Unit.GRAM.base_unit) 都返回相同的 id。所以没有多余的实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-30
    • 2014-04-24
    相关资源
    最近更新 更多