【问题标题】:How to make nested enum also have value如何使嵌套枚举也有价值
【发布时间】:2019-02-01 23:59:14
【问题描述】:

考虑以下代码示例:

from enum import Enum

class Location(Enum):
    Outside = 'outside'
    Inside = 'inside' 
    class Inside(Enum): # TypeError for conflicting names
        Downstairs = 'downstairs'
        Upstairs = 'upstairs'

如何使 Inside 具有“inside”的值,同时也是用于访问 Downstairs 和 Upstairs 的嵌套枚举?

所需输入:

print(Location.Inside)
print(Location.Inside.value)
print(Location.Inside.Downstairs)
print(Location.Inside.Downstairs.value)

期望的输出:

Location.Inside
inside
Location.Inside.Downstairs
downstairs

更新 1:

我的具体问题的更多背景:

class Location(Enum):
    Outside = 'outside'
    Inside = 'inside' 
    class Inside(Enum): # TypeError for conflicting names
        Downstairs = 'downstairs'
        Upstairs = 'upstairs'

class Human:
    def __init__(self, location):
        self.location = location

def getLocationFromAPI():
    # this function returns either 'inside' or 'outside'
    # make calls to external API  
    return location # return location from api in str

def whereInside(human):
    if human.location != Location.Inside:
        return None
    # here goes logic that determines if human is downstairs or upstairs
    return locationInside # return either Location.Downstairs or Location.Upstairs


location_str = getLocationFromAPI() # will return 'inside' or 'outside'
location = Location(location_str) # make Enum
human = Human(location) # create human with basic location
if human.location == Location.Inside:
    where_inside = whereInside(human)
    human.location = where_inside # update location to be more precise

问题是当我创建 Human 对象时,我只知道一个基本位置,例如“内部”或“外部”。只有在那之后,我才能更准确地更新位置。

【问题讨论】:

  • 枚举只能有一个值。
  • @juanpa.arrivillaga 啊哈,谢谢。您知道我发布的代码的其他设计选择吗?我认为我想要达到的目标很清楚。
  • 这对我来说没有多大意义,但是删除Inside = 'inside'
  • @Jaba 哇,非常感谢。我错过了。
  • 从根本上说你所要求的没有意义,任何对象的属性只能有一个值,并且属性不能同时是字符串'inside'和枚举Inside

标签: python python-3.x


【解决方案1】:

您可以通过将enum.Enum 嵌入到另一个中来完成此操作,如下所示:(请注意名称冲突)

from enum import Enum

class _Inside(Enum):
    Downstairs = 'downstairs'
    Upstairs = 'upstairs'

class Location(Enum):
    Outside = 'outside'
    Inside = _Inside 

print(Location.Inside.value.Downstairs.value)
downstairs

【讨论】:

  • 这比嵌套解决方案要简洁得多,但是,它对我的​​特定设计没有帮助,因为我无法使用它: Location('inside') - > Location.Inside
  • 请详细说明您将如何使用它,因为这似乎是回答您问题的最佳方式。
  • 我看到了你的编辑,为什么不在这里使用命名元组甚至字典?好像你可以。此外,您的错误似乎是由于您使用 Inside 然后创建了一个名为 Inside 的类。仅使用命名元组或字典可能会规避这一点
【解决方案2】:

可能有点晚了,提出问题的人不再需要,但我把它留在这里以防有人想看它,即使它已经被验证为一个,尽管同样的评论说它不完整。

但我一直在考虑它,最后我通过查看相同的文档解决了它XD。

你不能扩展 Enums 的类,但是你可以扩展方法,我一直遵循这种方式,我唯一做的就是覆盖 newinit方法,用例可以修改,这只是嵌套枚举数。

from enum import Enum

class SuperNestedEnum(Enum):
    def __new__(cls, *args):
        obj = object.__new__(cls)
        value = None
        # Normal Enumerator definition
        if len(args) == 1:
            value = args[0]

        # Have a tuple of values, first de value and next the nested enum (I will set in __init__ method)
        if len(args) == 2:
            value = args[0]

        if value:
            obj._value_ = value

        return obj

    def __init__(self, name, nested=None):
        # At this point you can set any attribute what you want
        if nested:
            # Check if is an Enumerator you can comment this if. if you want another object
            if isinstance(nested, EnumMeta):
                for enm in nested:
                    self.__setattr__(enm.name, enm)


class Homework(Enum):
    Task = "5"

class Subjects(SuperNestedEnum):
    Maths = "maths"
    English = "english"
    Physics = "nested", Homework

class School(SuperNestedEnum):
    Name = "2"
    Subjects = "subjects", Subjects

忽略用例,因为它没有意义,这只是一个例子

>>> School.Name
<School.Name: '2'>

>>> School.Subjects
<School.Subjects: 'subjects'>

>>> School.Subjects.value
'subjects'

>>> School.Subjects.Maths
<Subjects.Maths: 'maths'>

>>> School.Subjects.Physics.value
'nested'

>>> School.Subjects.Physics.Task
<Homework.Task: '5'>

>>> School.Subjects.Physics.Task.value
'5'

【讨论】:

    【解决方案3】:

    如果有人遇到类似问题,并且只想为该主题提供一个简单的解决方案,而无需为包含字符串的枚举修补任何函数或额外导入,请按照以下步骤操作:

    1. 创建值枚举,在您的较低层次结构中,例如:

      class __private_enum1__(str, enum.Enum):
          VAL11 = "abc"
          VAL12 = "def"
      
      class enum2(str, enum.Enum):
          VAL21 = "123"
          VAL22 = "456"
      
    2. 为这些枚举创建一个基类(一个容器)。您可以在其中导入枚举类或直接访问枚举。

       class myValues:
           VAL11 = __private_enum1__.VAL11
           VAL12 = __private_enum1__.VAL12
           VALS2X = enum2
      

    那么您可以通过以下方式访问您的价值观:

    print(myValues.VAL11.value)
    print(myValues.VAL2X.VAL21.value)
    

    .value 在这里不是必需的,但它表明您既可以访问枚举内部的字符串以将其传递给其他函数,也可以访问枚举本身,这非常简洁。所以基本上,首先创建值,然后是结构。这样你就有了一个类,但它为你提供了枚举的基本功能,你可以将它们嵌套到你想要的深度,而无需进一步导入。

    【讨论】:

      猜你喜欢
      • 2021-02-04
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多