我知道,here和there中已经存在类似的问题。但是他们的问题和答案并非我要寻找的。此外,他们是锁定问题,因此我无法为他们添加新答案。 SMH。
首先,让我们澄清问题以了解其范围。在像这样的其他静态语言中使用枚举时:
public enum Size
{
SMALL=0,
MIDIUM=1,
LARGE=2,
BIG=2 // There can possibly be an alias
}
我们希望它能帮助我们
var foo = Size.SMALL
有效,var bar = Size.SMAL
应该会产生糟糕的错误。HTTP404 = "Not Found", HTTP200 = "OK", ...
。 (因此,基于range(N)
的那些实现是不可接受的。)public void Foo(Size size) {...}
我还希望这些值成为我的Enum解决方案中的一等公民。就是说,我的函数def parser(value_from_the_wire): ...
想使用一些本机值(例如整数或字符串等),而不是使用Enum成员。这是Python 3中标准Enum中棘手的部分。
assert 2 == MY_ENUM.MY_VALUE
仅在从IntEnum
派生MY_ENUM时才有效(并且没有默认的StrEnum
,尽管不难自己一个子类化)assert 2 in MY_ENUM
不起作用,即使MY_ENUM是从IntEnum
派生的。答案 0 :(得分:1)
TL; DR :使用venum
因此,我满足该问题中3个条件的Python解决方案基于namedtuple,并且实现似乎比新的built-in Enum in Python 3更简单。
from collections import namedtuple
def enum(name=None, **kwargs):
"""
:param name: An optional type name, which only shows up when debugging by print(...)
"""
# This actual implementation below is just a one-liner, even within 80-char
return namedtuple(name or "Const_%d" % id(kwargs), kwargs.keys())(**kwargs)
用法现在很简单。
# definition syntax
SIZE = enum("Size", SMALL=0, MEDIUM=1, LARGE=2, BIG=2)
# usage on referencing
print(SIZE.SMALL) # got 0, instead of <SIZE.SMALL: 0>
try:
print(SIZE.SMAL) # got AttributeError
assert False, "should not arrive this line"
except AttributeError:
pass
# usage on comparison and contains-check
assert SIZE.MEDIUM == 1 # works. It won't work when using standard Enum (unless using IntEnum)
assert 1 in SIZE # works. It won't work when using standard Enum (unless you wrote it as SIZE(1)).
# usage on regulating input value
def t_shirt_size(size):
if size not in SIZE:
raise ValueError("Invalid input value")
print("Placing order with size: %s" % size)
t_shirt_size(SIZE.MEDIUM) # works
t_shirt_size(2) # also want this to work
try:
t_shirt_size(7) # got AssertionError
assert False, "This line should not be reached!"
except ValueError:
pass
编辑1:实际上,我知道有一个standard Enum module in Python 3,从功能上讲,它是我下面的单层实现的很大程度上超集。但是,在一种情况下,标准枚举不适合我的需求。我希望价值观成为我的枚举中的一等公民;我希望我的t_shirt_size(...)
函数接受一个实际值,而不仅仅是一个枚举成员。标准枚举方法不允许这两种用法:assert SIZE.MEDIUM == 1
或assert 1 in SIZE
。
编辑2:鉴于人们倾向于将此主题定型为重复,我计划将我的方法实际实现为带有大量文档的独立模块。我什至为它起了一个很酷的名字,venum
,V代表Value。就是在那个时候,我检查了pypi中的名称,发现已经有一个使用与我相同的方法和documented well使用相同名称的软件包。这样就解决了。我将简单地pip install venum代替。 :-)
答案 1 :(得分:0)
使用Python 3的Enum
:
from enum import IntEnum
class SIZE(Enum):
SMALL = 0
MEDIUM = 1
LARGE = 2
BIG = 2
@classmethod
def contains(cls, value):
return any([e.value == value for e in cls])
并使用:
print(SIZE.SMALL) # got <SIZE.SMALL: 0>
print(SIZE.SMAL) # got AttributeError
def t_shirt_size(size):
assert size in SIZE, "Invalid input value"
place_order_with_size(size)
t_shirt_size(SIZE.MEDIUM) # works
t_shirt_size(7) # got AssertionError