应该通过身份或平等来比较枚举实例吗?

时间:2014-09-15 23:33:01

标签: python enums

根据文档enum members are singletons

>>> from enum import Enum
>>> class Potato(Enum):
...     spud = 1234
...     chat = 1234
...     
>>> x = 1234
>>> y = 1234
>>> x is y
False
>>> x = Potato.spud
>>> y = Potato.chat
>>> x is y
True
>>> x.value is y.value
True

这是否意味着我们也应该通过身份来比较它们,就像PEP8建议我们应该总是使用的是/不是,而且从来都不是单身操作者,例如None"?

到目前为止,我一直在使用平等运营商,并且没有发现任何问题需要保证如PEP8警告的强烈措辞。如果有的话,为枚举实例使用相等的缺点到底是什么?或者它只是一个微优化?

3 个答案:

答案 0 :(得分:8)

来自https://docs.python.org/3/library/enum.html#module-enum

  

在枚举中,成员可以通过身份进行比较

特别是来自https://docs.python.org/3/library/enum.html#comparisons

  

枚举成员按身份进行比较

答案 1 :(得分:4)

首先,我们绝对可以排除x.value is y.value,因为那些不是单身人士,这些都是您存储在属性中的普通价值。

但是x is y呢?

首先,我认为,通过"像无和#34;这样的单身人士,PEP 8特别指的是一些小的,固定的内置单例,就像None一样重要。什么重要的方式?您为什么要将Noneis进行比较?

可读性:if foo is None:读起来就像它的意思。在极少数情况下,当您想要将True与其他真实值区分开来时,if spam is True:读取的内容优于if spam == True:,并且更明显地表明这不是一件轻浮的事情== True被不正确地遵循Python中的C ++编码标准的人使用。这可能适用于foo is Potato.spud,但不适用于x is y

用作哨兵:None用于表示"值丢失"或"搜索失败"或类似的情况。当然,在None本身可以是值的情况下,它不应该被使用。如果有人创建了一个实例比较等于None的类,那么在没有意识到的情况下可能会遇到这个问题。 is None可以防范这种情况。由于TrueFalse1 == True0 == False(在极少数情况下,当你想区分它们时)更是一个问题。这个原因似乎不适用于此处 - 如果1 == Potato.spud,那只是因为您有意选择使用IntEnum而不是Enum,在这种情况下,&None #39;正是你想要的......

(准)关键字状态:None和朋友们多年来逐渐从完全正常的内置关键字迁移到关键字。符号None的默认值不仅仅是单例,唯一的可能的值就是单例。这意味着优化器,静态linter等可以假设is在代码中的含义,以及它在运行时定义的任何方式。同样,这个原因似乎并不适用。

表现:这根本不是考虑因素。在某些实现中,与==进行比较而不是if devo is Potato.spud:进行比较可能会更快,但这实际上不太可能在实际代码中产生差异(或者,如果确实如此,实际代码可能需要更高级别的优化,例如将列表转换为集合......)。

那么,结论是什么?

嗯,这里很难摆脱意见,但我认为这样说是合理的:

  • if x is y:是合理的,如果它使事情更具可读性,但只要你在代码库中保持一致,我就不会认为任何人都会抱怨。
  • Potato,即使他们都知道是if x.value is Potato.spud.value个对象,也是不合理的。
  • {{1}}不合理。

答案 2 :(得分:2)

PEP 8说:

  

应该始终使用isis not来比较像None这样的单例,而不是等式运算符。

我不赞同abarnert:这不是因为这些是内置的或特殊的以任何方式。这是因为在这些情况下你关心 对象,而不是看起来像它的东西。

例如,当您使用is None时,您关心的是它是否 None ,而不是None None但是它确实有点重要。

举个例子:

no_argument = object()
def foo(x=no_argument):
    if x OP no_argument:
        ...
    ...

如果OPis,则这是完全惯用的代码。如果它是==,那就不是。

出于同样的原因,你应该这样做:

  • 如果你想要对鸭子类型进行相等,例如使用IntEnum或你想要进行子类化和覆盖的枚举(例如当你有方法和其他附加功能的复杂枚举类型时)它会使感觉使用==

  • 当您使用枚举作为愚蠢的哨兵时,请使用is