2015-11-12 14 views
14

EnumのタイプをPython 3.4で拡張するためのベストプラクティスは何ですか?またこれを行う可能性もありますか?例えばPython Enumを拡張するには?

from enum import Enum 

class EventStatus(Enum): 
    success = 0 
    failure = 1 

class BookingStatus(EventStatus): 
    duplicate = 2 
    unknown = 3 

Traceback (most recent call last): 
... 
TypeError: Cannot extend enumerations 

現在のメンバーと、基地列挙クラスを作成して(上記の例のように)他の列挙クラスでそれを使用するいかなる可能な方法は存在しません。 Python enumの継承を実装する他の方法はありますか?

+2

列挙型の背後にある考え方は、その型のすべての値の完全なリストがあることです。それを拡張してより多くの値を追加すると、enumの最も基本的な特性を破ります。 – user2357112

+0

@ user2357112:これは私の問題の答えです。 –

答えて

13

列挙型をサブクラス化することは、列挙型でメンバーが定義されていない場合にのみ許可されます。

メンバを定義するenumのサブクラス化を許可すると、型とインスタンスのいくつかの重要な不変量に違反することになります。

https://docs.python.org/3/library/enum.html#restricted-subclassing-of-enumerations

のでなし、それが直接ことはできません。

+0

これを行うための組み込みの方法はありますか? –

+0

@ falek.marcin:あなたはより多くの使用情報を提供する必要があります。 'BookingStatus'を' Enum'から直接継承させ、最初のものから名前の値を繰り返すことができます。軽く冗長で、相互運用性がない(別々のタイプです)が、値のセットを1つだけ使用している場合は問題ありません。 – ShadowRanger

+1

@ falek.marcin:恐らくそうではありません。あなたができる最良の方法は、Enumの別の簡単な実装を使うことです。 [たくさんある](http://stackoverflow.com/q/36932/3821804)。 – GingerPlusPlus

3

一般的ではありませんが、多くのモジュールから列挙型を作成すると便利なことがあります。

from aenum import Enum, extend_enum 

class Index(Enum): 
    DeviceType = 0x1000 
    ErrorRegister = 0x1001 

for name, value in (
     ('ControlWord', 0x6040), 
     ('StatusWord', 0x6041), 
     ('OperationMode', 0x6060), 
     ): 
    extend_enum(Index, name, value) 

assert len(Index) == 5 
assert list(Index) == [Index.DeviceType, Index.ErrorRegister, Index.ControlWord, Index.StatusWord, Index.OperationMode] 
assert Index.DeviceType.value == 0x1000 
assert Index.StatusWord.value == 0x6041 

情報開示:私はPython stdlib Enumの著者、enum34 backport、およびAdvanced Enumeration (aenum)ライブラリ午前aenum ライブラリはextend_enum機能でこれをサポートしています。

7

直接Enumクラスを呼び出してチェーンを使用すると、既存の列挙型を拡張(結合)できます。

CANopen の実装で作業しているときにenumを拡張する問題が発生しました。 0x1000から0x2000までの範囲のパラメータインデックス は、すべてのCANopenノードに対して一般的です。 0x6000 の範囲は以降など、ノードがドライブ、IOモジュールがあるかどうかをオープン依存

nodes.py:

from enum import IntEnum 

class IndexGeneric(IntEnum): 
    """ This enum holds the index value of genric object entrys 
    """ 
    DeviceType = 0x1000 
    ErrorRegister = 0x1001 

Idx = IndexGeneric 

drives.py:

from itertools import chain 
from enum import IntEnum 
from nodes import IndexGeneric 

class IndexDrives(IntEnum): 
    """ This enum holds the index value of drive object entrys 
    """ 
    ControlWord = 0x6040 
    StatusWord = 0x6041 
    OperationMode = 0x6060 

Idx= IntEnum('Idx', [(i.name, i.value) for i in chain(IndexGeneric,IndexDrives)]) 
+1

クール、感謝はうまくいくようです! – amohr

+1

非常に賢い。 +1 –

+0

私はMITライセンスの[typhonライブラリ](https://pypi.python.org/pypi/typhon)で最終的なスニペットから派生したコードを使用したいと思います。 MIT互換ライセンスのもとでこれを再ライセンスしますか?私は完全な帰属を保持します。 – gerrit

関連する問題