如何静态防止 str == 枚举比较?

How to statically protect against str == enum comparisons?

提问人:KamilCuk 提问时间:9/26/2023 最后编辑:KamilCuk 更新时间:10/11/2023 访问量:103

问:

我经常犯以下错误:

import enum

class StatusValues(enum.Enum):
    one = "one"
    two = "two"

def status_is_one(status: str):
    return status == StatusValues.one

String 永远不会是枚举类。问题是它应该是.StatusValues.one.value

是否有 -ish 函数,以便我的 pyright 会在我将字符串与类进行比较的行上出错?有没有很好的方法可以防止此类错误?strcmp(status, StatusValues.one)

python-3.x 枚举 python-3.7

评论

0赞 plamut 9/26/2023
你试过使用字符串枚举吗? (或在 Python 3.11+ 中)。使用字符串枚举,比较将成功,例如class StatusValues(str, enum.Enum):enum.StrEnumstatus = "one"; status == StatusValues.one
0赞 KamilCuk 9/26/2023
哇,这真是太棒了。我必须与python 3.7兼容。
1赞 plamut 9/26/2023
然后通过混合来定义枚举。:)好的,我正确地解决了这个问题,让我尽快写一个更详细的答案str
1赞 Abdul Aziz Barkat 9/26/2023
我从未使用过pyright,但是“reportUnnecessaryComparison”设置听起来像是您需要的。

答:

5赞 plamut 9/26/2023 #1

是的,这可能是一个问题:默认情况下,我们不能直接将字符串与枚举成员进行比较:

>>> status = "two"
>>> status == StatusValues.two
False

必须记住将字符串与枚举成员的字符串进行比较,这也有点冗长:.value

>>> "two" == StatusValues.two.value
True

幸运的是,有一个解决方案,甚至在文档中也提到过,但它曾经(在 Python 3.11 之前)在一个有点容易错过的部分(恕我直言)中。我们可以混合一种类型的枚举成员:

class IntEnum(int, Enum):
    pass

这演示了如何定义相似的派生枚举;例如,混合而不是 .strint

因此,解决方案是定义一个具有基类的枚举:str

class StatusValues(str, Enum):
    one = "one"
    two = "two"

>>> status = "two"
>>> status == StatusValues.two  # no .value
True

在 Python 3.11+ 中,StrEnum 已经包含在模块中,但您提到您仍然需要支持 Python 3.7。enum

评论

0赞 jonrsharpe 9/26/2023
请注意,这些混合枚举并不总是以可预测的方式运行: stackoverflow.com/q/77153859/3001761
0赞 plamut 9/26/2023
有趣,谢谢你的分享!幸运的是,这似乎是一个边缘案例,被 Enum 作者本人所劝阻,但还是很高兴了解它。
0赞 KamilCuk 9/27/2023
这是一个非常有用的答案。尽管多次阅读文档,但我不知道您可以同时从 str 和 Enum 继承来实现此行为。做 3.7 可移植性类非常容易,看起来像class MyStrEnum(str, Enum): def _generate_next_value_(name, *args): return name
0赞 plamut 9/27/2023
事实上,这正是我在几个项目中使用的(示例)。这样的类甚至在键入枚举成员的值时避免了重复(例如),我们可以说,保护我们免受字符串值中的拼写错误。foo = 'foo'foo = enum.auto()