枚举实例应该按同一性还是相等性进行比较?

新手上路,请多包涵

根据文档, 枚举成员是单例

 >>> 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 建议我们应该始终使用 is/is not 而永远不要使用相等运算符来表示“像 None 这样的单例”?

到目前为止,我一直在使用相等运算符,并且没有注意到任何问题可以保证像 PEP8 警告的那样强硬的措辞。如果有的话,对枚举实例使用相等的缺点到底是什么?或者它只是一个微优化?

原文由 wim 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

首先,我们绝对可以排除 x.value is y.value ,因为它们不是单例,它们是您存储在属性中的完全普通的值。

但是 x is y 呢?

首先,我认为,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 防止这种情况。这对于 TrueFalse 更成问题(同样,在你想要区分它们的极少数情况下),因为 1 == True 0 == False 。这个原因在这里似乎并不适用——如果 1 == Potato.spud ,那只是因为你有意选择使用 IntEnum 而不是 Enum 正是你想要的……

(准)关键字状态: None ,朋友们逐渐从完全正常的内置迁移到关键字。不仅符号的默认值 None 总是单例,唯一 可能的 值是单例。这意味着优化器、静态 linter 等可以假设 None 在你的代码中意味着什么,在某种程度上它不能用于运行时定义的任何东西。同样,这个原因似乎并不适用。

性能:这真的不是一个考虑因素。在某些实现上,与 is 进行比较可能比与 == 进行比较更快,但这不太可能对实际代码产生影响(或者,如果确实如此,那真正的代码可能需要更高层次的优化,比如把一个列表变成一个集合……)。

那么,结论是什么?

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

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

原文由 abarnert 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题