【问题标题】:How to compare a string with a python enum?如何将字符串与python枚举进行比较?
【发布时间】:2017-06-27 13:34:09
【问题描述】:

我刚刚发现 python 中存在 Enum 基类,我正在尝试想象它对我有什么用处。

假设我定义了一个红绿灯状态:

from enum import Enum, auto

class Signal(Enum):
    red = auto()
    green = auto()
    orange = auto()

假设我从程序中的某个子系统接收信息,以字符串的形式表示颜色名称,例如brain_detected_colour = "red"

如何将此字符串与我的交通灯信号进行比较?

显然,brain_detected_colour is Signal.redFalse,因为Signal.red 不是字符串。

Signal(brain_detected_colour) is Signal.redValueError: 'red' is not a valid Signal 失败。

【问题讨论】:

    标签: python enums python-3.6


    【解决方案1】:

    一个人不会创建instance of an EnumSignal(foo) 语法用于按值访问 Enum 成员,当它们是 auto() 时不打算使用。

    但是,可以使用字符串到access Enum members,就像使用方括号访问dict 中的值一样:

    Signal[brain_detected_colour] is Signal.red
    

    另一种可能性是将字符串与枚举成员的name 进行比较:

    # Bad practice:
    brain_detected_colour is Signal.red.name
    

    但在这里,我们不是在测试 Enum 成员之间的身份,而是比较字符串,所以最好使用相等测试:

    # Better practice:
    brain_detected_colour == Signal.red.name
    

    (感谢string interning,字符串之间的身份比较有效,最好不要依赖它。感谢@mwchase 和@Chris_Rands 让我意识到这一点。)

    另一种可能性是在创建 Enum 时将成员值显式设置为其名称:

    class Signal(Enum):
        red = "red"
        green = "green"
        orange = "orange"
    

    (请参阅this answer 了解自动化的方法。)

    那么,Signal(brain_detected_colour) is Signal.red 将是有效的。

    【讨论】:

    • brain_detected_colour is Signal.red.name 中使用is 是有风险的;最好使用==
    • @mwchase 您能否解释一下原因,以便我编辑答案并添加解释?
    • 你依赖于字符串实习,模糊的实现细节guilload.com/python-string-interning,除非你真的需要比较对象的身份,否则永远不要使用is
    • 解决了我的问题。虽然我不能使用Signal(brain_detected_colour) is Signal.red(在答案末尾提到,因为当使用字符串值构建枚举时)......但是Signal[brain_detected_colour] == Signal.red 确实有效。请注意,我考虑了使用==进行比较风险较小的评论。
    • 是的,我在将枚举值与字符串进行比较时遇到了同样的问题,虽然它们具有相同的字符串值,但使用“is”它不起作用,使用 == 解决了我的问题
    【解决方案2】:

    更好的做法是从str 继承Signal

    class Signal(str, Enum):
        red = 'red'
        green = 'green'
        orange = 'orange'
    
    brain_detected_colour = 'red'
    brain_detected_colour == Signal.red  # direct comparison
    

    【讨论】:

    • 你能在答案中解释一下,为什么这是一个更好的做法?
    • 以防万一您仍然想知道为什么更好地使用 mixin str docs.python.org/3/library/enum.html#others
    • 这对我有用。 @MartinGrey 这可能是因为您将 string 类型与 enum 类型进行了比较。当枚举类中不存在str 时,我正在将字符串与枚举进行比较。 (我猜,分配字符串值是不够的。)
    【解决方案3】:

    可以让auto() 返回枚举成员的名称作为其值(在auto section of the docs1:

    class AutoName(Enum):
        def _generate_next_value_(name, start, count, last_values):
            return name
    
    class Ordinal(AutoName):
        NORTH = auto()
        SOUTH = auto()
        EAST = auto()
        WEST = auto()
    

    并在使用中:

    >>> list(Ordinal)
    [<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]
    

    1 这需要 Python 3.6 或 aenum 2.02 版本(aenum 可用于 2.7 之前的 Python)。

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

    【讨论】:

    • 不幸的是,虽然下面的断言失败了:assert Ordinal.NORTH == "NORTH" 所以你不能直接比较一个字符串。编辑:哦,这可以通过使用class Ordinal(str, AutoName)来工作。
    • 您介意编辑代码以便复制粘贴吗?
    【解决方案4】:
    class Signal(Enum):
        red = auto()
        green = auto()
        orange = auto()
    
        def equals(self, string):
           return self.name == string
    
    brain_detected_colour = "red"
    
    if Signal.red.equals(brain_detected_colour):
       #something awesome
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多