<p><em>更新:2017-03-01</em></p>
<blockquote>
<p>In Python 3.6 (and <a href="https://pypi.python.org/pypi/aenum" rel="nofollow noreferrer"><code>Aenum 2.0</code></a><sup>1</sup>) <a href="https://docs.python.org/3/library/enum.html#flag" rel="nofollow noreferrer"><code>Flag</code></a> and <a href="https://docs.python.org/3/library/enum.html#intflag" rel="nofollow noreferrer"><code>IntFlag</code></a> classes have been added; part of that was a new <a href="https://docs.python.org/3/library/enum.html#using-automatic-values" rel="nofollow noreferrer"><code>auto()</code> helper</a> that makes this trivially easy:</p>
</blockquote>
<pre><code>>>> 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'>]
</code></pre>
<hr/>
<p><em>原始答案</em></p>
<p>使用<code>AutoStr</code>类的困难在于枚举成员的名称没有传递到创建它的代码中,因此无法使用它。另一个问题是<code>str</code>是不可变的,因此我们不能在创建枚举之后更改这些类型(例如,通过使用<a href="https://wiki.python.org/moin/PythonDecorators" rel="nofollow noreferrer">class decorator</a>)。</p>
<p>最简单的方法是使用<a href="https://docs.python.org/3/library/enum.html#functional-api" rel="nofollow noreferrer">Functional API</a>:</p>
<pre><code>Animal = Enum('Animal', [(a, a) for a in ('horse', 'dog')], type=str)
</code></pre>
<p>这给了我们:</p>
<pre><code>>>> list(Animal)
[<Animal.horse: 'horse'>, <Animal.dog: 'dog'>]
>>> Animal.dog == 'dog'
True
</code></pre>
<hr/>
<p>下一个最简单的事情是,假设您想为将来的枚举使用创建一个基类,那么它将类似于my<code>DocEnem</code>:</p>
<pre><code>class DocEnum(Enum):
"""
compares equal to all cased versions of its name
accepts a doctring for each member
"""
def __new__(cls, *args):
"""Ignores arguments (will be handled in __init__)"""
obj = object.__new__(cls)
obj._value_ = None
return obj
def __init__(self, doc=None):
# first, fix _value_
self._value_ = self._name_.lower()
self.__doc__ = doc
def __eq__(self, other):
if isinstance(other, basestring):
return self._value_ == other.lower()
elif not isinstance(other, self.__class__):
return NotImplemented
return self is other
def __hash__(self):
# keep DocEnum hashable
return hash(self._value_)
def __ne__(self, other):
return not self == other
</code></pre>
<p>使用中:</p>
<pre><code>class SpecKind(DocEnum):
REQUIRED = "required value"
OPTION = "single value per name"
MULTI = "multiple values per name (list form)"
FLAG = "boolean value per name"
KEYWORD = 'unknown options'
</code></pre>
<p>注意,与第一个选项不同,<code>DocEnum</code>成员是<em>而不是</em><code>str</code>s</p>
<hr/>
<p>如果你想用困难的方法:子类<code>EnumMeta</code>,并在创建成员之前修改新的<code>Enum</code>类字典:</p>
<pre><code>from enum import EnumMeta, Enum, _EnumDict
class StrEnumMeta(EnumMeta):
def __new__(metacls, cls, bases, oldclassdict):
"""
Scan through `oldclassdict` and convert any value that is a plain tuple
into a `str` of the name instead
"""
newclassdict = _EnumDict()
for k, v in oldclassdict.items():
if v == ():
v = k
newclassdict[k] = v
return super().__new__(metacls, cls, bases, newclassdict)
class AutoStrEnum(str, Enum, metaclass=StrEnumMeta):
"base class for name=value str enums"
class Animal(AutoStrEnum):
horse = ()
dog = ()
whale = ()
print(Animal.horse)
print(Animal.horse == 'horse')
print(Animal.horse.name, Animal.horse.value)
</code></pre>
<p>这给了我们:</p>
<pre><code>Animal.horse
True
horse horse
</code></pre>
<hr/>
<p><sup>1</sup>披露:我是<a href="https://docs.python.org/3/library/enum.html" rel="nofollow noreferrer">Python stdlib ^{<cd7>}</a>、<a href="https://pypi.python.org/pypi/enum34" rel="nofollow noreferrer">^{<cd9>} backport</a>和<a href="https://pypi.python.org/pypi/aenum" rel="nofollow noreferrer">Advanced Enumeration (^{<cd10>})</a>库的作者。</p>