2010-12-17 17 views
8

(ハック)はPythonに列挙型を実装するための単純な方法を、私を見つけた:Pythonの列挙型クラス

class MyEnum: 
    VAL1, VAL2, VAL3 = range(3) 

私はそのようなとしてこれを呼び出すことができます。

bob = MyEnum.VAL1 

セクシー!

さて、文字列が与えられている場合は数値を、数値が与えられている場合は文字列を取得できます。のは、私が正確に一致する文字列をしたいとしましょう列挙型キーの

私は考えることができる最高のは、このようなものです:

class MyEnum: 
    VAL1, VAL2, VAL3 = range(3) 
    @classmethod 
    def tostring(cls, val): 
    if (val == cls.VAL1): 
     return "VAL1" 
    elif (val == cls.VAL2): 
     return "VAL2" 
    elif (val == cls.VAL3): 
     return "VAL3" 
    else: 
     return None 
    @classmethod 
    def fromstring(cls, str): 
    if (str.upper() == "VAL1"): 
     return cls.VAL1 
    elif (str.upper() == "VAL2"): 
     return cls.VAL2 
    elif (str.upper() == "VAL2"): 
     return cls.VAL2 
    else: 
     return None 

またはそのような何か(私は無効な例をキャッチしていますどのように無視します)

私が上でやっていることを行うためのより良い、より多くのpython中心の方法がありますか?または、すでに上のように簡潔になっています。

これを行うにはより良い方法があるようです。

+4

場合/他のこの量は、常に、それは間違っているソリューションです示し;)の –

+0

可能重複[Pythonで「列挙型」を実施するための最良の方法は何ですか? ](http://stackoverflow.com/questions/36932/whats-the-best-way-to-implement-an-enum-in-python) –

+0

@ニック:あなたの受け入れられた答えを変更することができます。 –

答えて

10

さて、ここであなたが尋ねたものです:

class MyEnum: 
    VAL1, VAL2, VAL3 = range(3) 
    @classmethod 
    def tostring(cls, val): 
    for k,v in vars(cls).iteritems(): 
     if v==val: 
      return k 

    @classmethod 
    def fromstring(cls, str): 
     return getattr(cls, str.upper(), None) 

print MyEnum.fromstring('Val1') 
print MyEnum.tostring(2) 

しかし、私は本当にPythonで列挙型のポイントを得ることはありません。それは、そのような豊富なタイプのシステムと、州を管理するジェネレータとコルーチンを備えています。

私は多分あなたはそれらを取り除くことができ、私は12年以上のためにPythonで列挙型を使用していませんでした知っている、あまりにも;-)

+0

MyEnum.tostring(3)はNoneを返します。私はおそらくrange'が0 'のtoString(2)で始まり'ためです(MyEnum.VAL3) – Rod

+0

が '' VAL3'与えMyEnum.tostringする必要があります。不幸な名前( '* [1-9]')。 Afaik、C/C++の 'enum'も0から始まります。 – delnan

+0

@delnan真。私は私の側でやったテストから混乱していた。おそらくtostringメソッドでintを直接使用することを妨げた副作用でしょう。 – Rod

1

あなたは辞書を使用することができます。

class MyEnum: 
    VAL1, VAL2, VAL3 = range(3) 
    __toString = { VAL1 : "VAL1", VAL2 : "VAL2", VAL3 : "VAL3" } 

    @classmethod 
    def tostring(cls, val): 
     return cls.__toString.get(val) 

    @classmethod 
    def fromstring(cls, str): 
     i = str.upper() 
     for k,v in cls.__toString.iteritems(): 
      if v == i: 
       return k 
     return None 


print MyEnum.tostring(MyEnum.VAL1) 
print MyEnum.fromstring("VAL1") 

編集:THC4k答えは間違いなく良いです。しかし、純粋な実装の例として私を残しました。

+2

先頭のダブルアンダースコア(=名前のマングリング)は...悪いのではなく、悪いことではありませんが、ちょうどそれらを壊す通常のケースを使用するのではなく、 @delnan。 – delnan

+0

私はこれに注意します。 – Rod

7

辞書を使用します。

MyEnum = {'VAL1': 1, 'VAL2':2, 'VAL3':3} 

休講必要。 Dictsはあなたのクラスビートを持っています。なぜなら、彼らは信じられないほど効率的ですから、2)信じられないほどの方法が焼き付けられています.3)は普遍的な言語構造です。それらも拡張可能です:

PythonでC++(または別の言語の)機能を実装することは賢明ではありません。あなたが "enum"のようなものを見つけたら、あなたはそれをPythonのやり方ではないと賭けることができます。

逆の場合は別のdictを作成してください。 (例えば。{'1':'VAL1', ...}

+2

逆に2番目の辞書を作成しなければならない場合、それはどの言語でも優先される単一ポイントの値に違反します。あなたはその懸念にどのように反応しますか? – Stabledog

+1

拡張性はenumの機能ではありません。 –

3

参照: How can I represent an 'Enum' in Python?

この1つは興味深いです:

class EnumMeta(type): 
    def __getattr__(self, name): 
    return self.values.index(name) 

    def __setattr__(self, name, value): # this makes it read-only 
    raise NotImplementedError 

    def __str__(self): 
    args = {'name':self.__name__, 'values':', '.join(self.values)} 
    return '{name}({values})'.format(**args) 

    def to_str(self, index): 
    return self.values[index] 

class Animal(object): 
    __metaclass__ = EnumMeta 
    values = ['Horse','Dog','Cat'] 

用途:

In [1]: Animal.to_str(Animal.Dog) 
Out[1]: 'Dog' 
In [2]: Animal.Dog 
Out[2]: 1 
In [3]: str(Animal) 
Out[3]: 'Animal(Horse, Dog, Cat)' 

それはシンプルで軽量です。このアプローチの欠点はありますか?

EDIT: AFAIK列挙型は概念として非常にpythonicではありません。なぜなら、それらが最初に実装されなかった理由です。私は決してそれらを使用していないし、Pythonでそれらのためのusecaseを見ることができません。

0

あなたがクラス内に自分の価値観をハードコーディングする必要はありません) - あなたはより良い列挙子の工場を持っている。彼らは、動的ではありませんので、列挙型は、静的型付け言語で有用です。その時 ながら、ちょうど例えば、represntationメソッドをオーバーライドし、Pythonが提供されるいくつかのnicetirsを追加、または属性の取得:

class Enumerator(object): 
    def __init__(self, *names): 
     self._values = dict((value, index) for index, value in enumerate (names)) 
    def __getattribute__(self, attr): 
     try: 
      return object.__getattribute__(self,"_values")[attr] 
     except KeyError: 
      return object.__getattribute__(self, attr) 
    def __getitem__(self, item): 
     if isinstance (item, int): 
      return self._values.keys()[self._values.values().index(item)] 
     return self._values[item] 
    def __repr__(self): 
     return repr(self._values.keys()) 

今まさにそれを使用します。

>>> enum = Enumerator("val1", "val2", "val3") 
>>> enum 
['val3', 'val2', 'val1'] 
>>> enum.val2 
1 
>>> enum["val1"] 
0 
>>> enum[2] 
'val3' 

で(ところで、人々 Python開発者のリストは、これについて話しているでしょう。ほとんどの場合、 はより完全で十分な機能を備えています。

3

これはあなたが望むことを行い、実装スライグを一般化します新しいPythonの列挙は最終的に3.4、およびhas also been backportedに上陸した

class EnumBase: # base class of all Enums 
    @classmethod 
    def tostring(cls, value): 
     return dict((v,k) for k,v in cls.__dict__.iteritems())[value] 

    @classmethod 
    def fromstring(cls, name): 
     return cls.__dict__[name] 

class MyEnum(EnumBase): VAL1, VAL2, VAL3 = range(3) 

print MyEnum.fromstring('VAL1') 
# 0 
print MyEnum.tostring(1) 
# VAL2 
18

[時間が経過...]

:htlyボイラープレートコードを削減します。あなたの質問への答えは今それを使用することです。 :)


例:

>>> from enum import Enum 
>>> class Modes(Enum) : 
... Mode1 = "M1" 
... Mode2 = "M2" 
... Mode3 = "M3" 
... 

>>> Modes.Mode1 
<Modes.Mode1: 'M1'> 

>>> Modes.Mode1.value 
'M1' 

>>> Modes.Mode1.value 
'M1' 

>>> Modes['Mode1'] # index/key notation for name lookup 
<Modes.Mode1: 'M1'> 

>>> Modes('M1')  # call notation for value lookup 
<Modes.Mode1: 'M1'> 

>>> Modes("XXX")  # example error 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Anaconda3\lib\enum.py", line 291, in __call__ 
    return cls.__new__(cls, value) 
    File "C:\Anaconda3\lib\enum.py", line 533, in __new__ 
    return cls._missing_(value) 
    File "C:\Anaconda3\lib\enum.py", line 546, in _missing_ 
    raise ValueError("%r is not a valid %s" % (value, cls.__name__)) 
ValueError: 'XXX' is not a valid Modes