2012-10-10 22 views
10

关于如何在Python中实现枚举,有几个问题。大多数解决方案最终会被或多或少相当于是这样的:没有枚举的pythonic设计

class Animal: 
    DOG=1 
    CAT=2 

别人有建议兴建枚举更复杂的方式,但ultimatly的倾向,当一切都说过和做过,看起来像这样的例子。

基于我在Java和C#中的经验,我可以想到这样一个习惯用法的各种用法。然而,它似乎并不是Pythonic。事实上,似乎每当有人问你为什么在Python中没有枚举时,你往往会发出一些呻吟声,关于如何没有理由尝试和用像Python这样的语言来强化编译时类型安全性,或者需要枚举的设计如何在Python中产生不好的气味。

我的问题不是如何在Python中实现枚举,而是一般人如何解决问题的方法,这些问题可以用Pythonic的方式枚举。换句话说,您如何解决一个问题,该问题有助于将数据类型与一组可能的值分离开来,而无需将Java/C#解决方案移植到Python。

+2

我不明白为什么你给的例子是非pythonic。如果我正在实现一个状态机,我将利用函数作为对象并将我的状态定义为函数。 –

+0

我不知道这个枚举是如何实现的,但是我只是觉得Python社区中的一些人认为需要枚举的解决方案首先是非Pythonic。你的建议是,使用第一类函数作为状态来实现状态机是一个很好的开始,但答案是! – jlund3

回答

4

PEP 435刚刚被接受,它将enum包与Enum类以及其他衍生物(如IntEnum)一起添加到标准库。这意味着从Python 3.4开始,在设计中使用枚举的“pythonic”方法就是使用这个包。它会是这个样子:

>>> from enum import Enum 
>>> class Color(Enum): 
... red = 1 
... green = 2 
... blue = 3 

>>> print(Color.red) 
Color.red 

>>> print(Color.red.name) 
red 

>>>> for color in Color: 
....  print(color) 
Color.red 
Color.green 
Color.blue 

这种设计的主要特点是,键可以拒绝比较,它没有任何意义(不像在其他的答案提出的字符串键),允许按键都还印刷与键值无关,并且通过定义Enum子类上的方法给出键值特殊属性,以及用户尝试使用Enum类中的非法键时引发显式和可理解错误的属性。

+0

只有缺点是:在Python 3.4之前是行不通的,到现在为止(2013年10月)还没有大的发行版。所以,让我们等着喝茶。 – nerdoc

+1

用于Python 2.4+的PEP 435的backport可以在PyPI上作为[enum34](https://pypi.python.org/pypi/enum34/)获得。虽然它是非官方的,但它是由PEP 435合着者Ethan Furman撰写的。 – tawmas

1

不是来自C#或Java背景我还是不太明白这个对枚举的兴趣。

根据我的理解,我可能会回到django风格,将任何必要的常量放在设置文件中并在必要时导入。

settings.py/animals.py

DOG = 1 
CAT = 2 

其他文件:

from animals import CAT, DOG 

甚至...

settings.py

ANIMALS = { "DOG": 1, "CAT": 2} 

其他的文件:

from settings import ANIMALS 

my_animal = "FROG" 
if my_animal not in ANIMALS.keys(): 
    print "new species discovered!" 
+2

'如果my_animal不在ANIMALS.keys()中:'实际上(a)更长和(b)效率更低,比简单检查'if my_animal not in ANIMALS'。 – Amber

+2

我认为这个例子强调了为什么接触Java/C#的人想要在Python中枚举。接受鸭子打字是一回事,凡是知道如何庸俗的东西都可以接受。对于一个Java/C#人来说,这是一个完全不同的事情,说你的语言允许简单的拼写错误来把你搞砸。例如,假设我输入my_animal =“dog”而不是my_animal =“DOG”并以某种方式发现了一个新物种?有一个枚举,你可以说my_animal = Animal.DOG为你节省点痛苦,因为你会在运行时得到一个AttributeError在你的脸上,而不是发现的物种错误。 – jlund3

+0

的确,我只是想明确地表明正在做什么,因为新来者不清楚替代方案正在做什么。 – monkut

3

因为Python的字符串是不可变的(和Python实习生他们在其认为必要的),有没有一个真正的特定优势,使用数字枚举换套的东西。相反,您可以简单地使用字符串的frozensettuple(取决于您是否在意订购)。

另一方面,如果你关心的是命名空间,使一个类的东西属性工作得很好。

正如在评论中提到的,如果你正在寻找类似于状态机实现的东西,那么一流的功能就是你的朋友。

+0

..如果你关心命名空间*和*你正在使用3.3,那么这个配方:http://code.activestate.com/recipes/578279-using-chainmap-for-embedded-namespaces/?in=lang -python –

+1

如果你使用3.3,你可以使用['types.SimpleNamespace'](http://docs.python.org/py3k/whatsnew/3.3.html#simplenamespace):) –

-1

我不相信C#中的枚举。对于国家机器,你有战略模式。而不是看对象的状态并决定要做什么。封装对象本身要做什么的逻辑。

这是Python中的一种自然方法,向我引入枚举只是鼓励糟糕的代码。

+0

这个问题不是专门谈论状态机。我同意在C#和Python枚举中都不是实现状态机的方法。然而,我们正在谈论的是代表一种具有一小组命名值的类型。对于涉及这种数据类型的问题,枚举非常有用。 – jlund3

+0

对我来说,这听起来像继承。一种具有一小组命名值的类型。同样,python第一次没有包含枚举就正确了。 –

+0

使用继承来创建具有相同父类的多个数据类型与使用具有一组可能值的单个数据类型是不一样的... – jlund3