我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
遵循Aaron Maenpaa提出的类Java枚举实现,我得出了以下结论。我们的想法是使它具有通用性和可解析性。
class Enum:
#'''
#Java like implementation for enums.
#
#Usage:
#class Tool(Enum): name = 'Tool'
#Tool.DRILL = Tool.register('drill')
#Tool.HAMMER = Tool.register('hammer')
#Tool.WRENCH = Tool.register('wrench')
#'''
name = 'Enum' # Enum name
_reg = dict([]) # Enum registered values
@classmethod
def register(cls, value):
#'''
#Registers a new value in this enum.
#
#@param value: New enum value.
#
#@return: New value wrapper instance.
#'''
inst = cls(value)
cls._reg[value] = inst
return inst
@classmethod
def parse(cls, value):
#'''
#Parses a value, returning the enum instance.
#
#@param value: Enum value.
#
#@return: Value corresp instance.
#'''
return cls._reg.get(value)
def __init__(self, value):
#'''
#Constructor (only for internal use).
#'''
self.value = value
def __str__(self):
#'''
#str() overload.
#'''
return self.value
def __repr__(self):
#'''
#repr() overload.
#'''
return "<" + self.name + ": " + self.value + ">"
其他回答
对于旧的Python 2.x
def enum(*sequential, **named):
enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
return type('Enum', (), enums)
如果你命名它,是你的问题,但如果不创建对象而不是值允许你这样做:
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False
当使用这里的其他实现时(在我的例子中使用命名实例时),必须确保永远不要尝试比较来自不同枚举的对象。这里有一个可能的陷阱:
>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True
呵!
Enum类可以是一行程序。
class Enum(tuple): __getattr__ = tuple.index
如何使用它(正向和反向查找、键、值、项等)
>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
遵循Aaron Maenpaa提出的类Java枚举实现,我得出了以下结论。我们的想法是使它具有通用性和可解析性。
class Enum:
#'''
#Java like implementation for enums.
#
#Usage:
#class Tool(Enum): name = 'Tool'
#Tool.DRILL = Tool.register('drill')
#Tool.HAMMER = Tool.register('hammer')
#Tool.WRENCH = Tool.register('wrench')
#'''
name = 'Enum' # Enum name
_reg = dict([]) # Enum registered values
@classmethod
def register(cls, value):
#'''
#Registers a new value in this enum.
#
#@param value: New enum value.
#
#@return: New value wrapper instance.
#'''
inst = cls(value)
cls._reg[value] = inst
return inst
@classmethod
def parse(cls, value):
#'''
#Parses a value, returning the enum instance.
#
#@param value: Enum value.
#
#@return: Value corresp instance.
#'''
return cls._reg.get(value)
def __init__(self, value):
#'''
#Constructor (only for internal use).
#'''
self.value = value
def __str__(self):
#'''
#str() overload.
#'''
return self.value
def __repr__(self):
#'''
#repr() overload.
#'''
return "<" + self.name + ": " + self.value + ">"
虽然最初的全会提案PEP 354在几年前被否决,但它不断被提出。本打算将某种enum添加到3.2,但它被推回到3.3,然后被遗忘。现在有一个PEP 435打算包含在Python 3.4中。PEP 435的参考实现是flufl.enum。
截至2013年4月,似乎有一个普遍的共识,即应该在3.4的标准库中添加一些东西——只要人们能够就“一些东西”应该是什么达成一致。这是最难的部分。看看从这里和这里开始的线程,以及2013年初的六个其他线程。
与此同时,每次出现这个问题时,PyPI、ActiveState等上都会出现大量的新设计和实现,所以如果你不喜欢FLUFL设计,可以尝试一下PyPI搜索。
枚举已按照PEP 435中的描述添加到Python 3.4。它还被反向移植到pypi上的3.3、3.2、3.1、2.7、2.6、2.5和2.4。
对于更高级的Enum技术,请尝试aenum库(2.7,3.3+,与enum34是同一作者)。py2和py3之间的代码并不完全兼容,例如,你需要在python 2中使用__order__)。
要使用enum34,执行$ pip install enum34 要使用aenum,执行$ pip install aenum
安装enum(没有编号)将安装一个完全不同且不兼容的版本。
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
或者说:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
在早期版本中,完成枚举的一种方法是:
def enum(**enums):
return type('Enum', (), enums)
是这样使用的:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
你也可以很容易地支持自动枚举,就像这样:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
并像这样使用:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
支持将值转换回名称可以这样添加:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
这将覆盖带有该名称的任何内容,但对于在输出中呈现枚举非常有用。如果反向映射不存在,它将抛出一个KeyError。第一个例子:
>>> Numbers.reverse_mapping['three']
'THREE'
如果你使用MyPy,另一种表达“枚举”的方式是typing.Literal。
例如:
from typing import Literal #python >=3.8
from typing_extensions import Literal #python 2.7, 3.4-3.7
Animal = Literal['ant', 'bee', 'cat', 'dog']
def hello_animal(animal: Animal):
print(f"hello {animal}")
hello_animal('rock') # error
hello_animal('bee') # passes