【问题标题】:Iterate or index list based on Enum基于枚举迭代或索引列表
【发布时间】:2019-09-16 00:51:22
【问题描述】:

我有一个包含 4 个元素的小枚举列表 (class Type(Enum): One,Two,Three,Four),我想知道是否有办法将枚举与全局列表 (List = [Type(0),Type(1),Type(2),Type(3)] 相关联。

我知道我可以使用语法List[ Type.Two.value ] 访问此列表。但我希望有一种简单的方法可以丢失.value。这不是打字问题——我不介意输入长的描述性变量名。但是列表和枚举是直接相关/关联的,因此如果列表将枚举视为迭代器,那将是更可取的。有没有简单的方法来解决这个问题?

我在 Blender 环境中工作,构建一个附加组件,如果这有什么不同的话。我对 python 也很陌生 - 大约一周大,所以如果你有明显的点,请不要忽略它们。

我对 C/C++ 非常熟悉,以防有任何相似之处。我非常喜欢创建数据库列表和关联迭代器类型,以防止使用与其关联的索引类型名以外的任何内容访问列表(所以你不会犯像Cars[my_boat_index] 这样的错误)

感谢任何建议!

【问题讨论】:

    标签: python python-3.x list enums enumeration


    【解决方案1】:

    Enum 转换为列表非常简单:

    list(Type)
    # [<Type.ONE: 1>, <Type.TWO: 2>, <Type.THREE: 3>, <Type.FOUR: 4>]
    

    使用Type 成员作为索引访问列表有点复杂:

    • 默认情况下,成员值从 1 开始
    • 但容器索引从 0 开始
    • 并且成员没有__index____int__ 方法

    简单/简单的解决方案是双重的:

    • 使用IntEnum 而不是Enum
    • 0开始计数

    所以:

    class Type(IntEnum):
        ZERO = 0
        ONE = 1
        TWO = 2
        THREE = 3
    

    IntEnum 成员可以在int 所在的任何地方使用,因此它们可以作为索引值正常工作。

    更复杂的解决方法是使用一个正则的Enum,把你需要的方法加进去,返回值的时候减1:

    class Type(Enum):
        ONE = 1
        TWO = 2
        THREE = 3
        FOUR = 4
    
        def __index__(self):
            return self.value - 1
    
        def __int__(self):
            return self.value - 1
    

    即使你添加了 __index____int__ 方法,你仍然应该从零开始计数,而不是做减一的技巧,因为当你习惯了 Python 的方式时,这会导致更多的问题有效。

    【讨论】:

    • 看起来 IntEnum 很适合我的情况。谢谢你这么详细的解释。
    【解决方案2】:

    来自文档https://docs.python.org/3/library/enum.htmlEnumerations support iteration, in definition order,因此您可以遍历它们以构建列表,例如:

    from enum import Enum
    
    class Numbers(Enum):
        ONE = 1
        TWO = 2
        THREE = 3
    
    assert [Number.value for Number in Numbers]  == [1,2,3]
    
    
    

    【讨论】:

      【解决方案3】:

      您似乎希望通过将索引类型限制为特定类型(例如枚举)来限制对列表的访问。

      虽然我不认为这是一个好主意,但你绝对可以做到:

      from enum import Enum
      
      
      class MyEnum(Enum):
          ZERO = 0
          ONE = 1
          TWO = 2
      
      
      class MyList(list):
          def __getitem__(self, item):
              assert isinstance(item, MyEnum)
              return super().__getitem__(item.value)
      
      
      ml = MyList([1, 2, 3])
      print(ml[MyEnum.ONE])
      print(ml[1])  # error here
      

      您为什么要将对列表的访问限制为与列表索引的默认类型(即int)不同的类型?

      如果您希望拥有特定的属性,为什么不定义一个类,或者如果您想通过特定的值进行索引,为什么不使用 dict?

      也许您应该提供一些关于您实际希望做什么的信息 - Python 不是 C/C++,它可能有一些完全有效的方式来做您想做的事情,而不必模仿 C/C++ 所做的事情而是。

      如果您不希望限制,而只是进行迭代(这似乎与问题所述不同):

      for my_value in MyEnum:
          print(ml[my_value])
      

      如果您不想限制仅访问该类型的索引,则可以省略 assert 语句。

      【讨论】:

      • 我不是要限制对列表的访问。只需使用枚举器值进行迭代。在为属性定义自定义类型时,Blender 环境似乎非常严格,所以我不确定我能摆脱什么。至于 C/C++,我刚刚提到我对它很熟悉,以防万一有任何相似之处可以使 python 的情况更容易解释。没有其他原因。感谢您向我展示这种类型的设置。我不确定 Blender 是否允许我创建具有自定义列表类型的属性组,但无论如何我都会尝试一下。
      猜你喜欢
      • 2017-06-24
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 2011-02-07
      • 2020-04-03
      • 2022-12-05
      • 2017-06-07
      • 1970-01-01
      相关资源
      最近更新 更多