39

検討:

class Item:
   def __init__(self, a, b):
       self.a = a
       self.b = b

class Items:
    GREEN = Item('a', 'b')
    BLUE = Item('c', 'd')

単純な列挙型のアイデアをこのケースに適合させる方法はありますか?(この質問を参照してください)理想的には、Javaの場合と同様に、すべてを1つのクラスに詰め込みたいと思います。

Javaモデル:

enum EnumWithAttrs {
    GREEN("a", "b"),
    BLUE("c", "d");

    EnumWithAttrs(String a, String b) {
      this.a = a;
      this.b = b;
    }

    private String a;
    private String b;

    /* accessors and other java noise */
}
4

7 に答える 7

39

Python 3.4には新しい列挙型データ型があります(これは1としてバックポートされenum34拡張されaenumています)。と2はどちらも、ユースケースを簡単にサポートします。enum34aenum

  • aenum(Python 2/3)

      import aenum
      class EnumWithAttrs(aenum.AutoNumberEnum):
          _init_ = 'a b'
          GREEN = 'a', 'b'
          BLUE = 'c', 'd'
    
  • enum34(Python 2/3)または標準ライブラリenum(Python 3.4以降)

      import enum
      class EnumWithAttrs(enum.Enum):
    
          def __new__(cls, *args, **kwds):
              value = len(cls.__members__) + 1
              obj = object.__new__(cls)
              obj._value_ = value
              return obj
          def __init__(self, a, b):
              self.a = a
              self.b = b
    
          GREEN = 'a', 'b'
          BLUE = 'c', 'd'
    

そして使用中:

>>> EnumWithAttrs.BLUE
<EnumWithAttrs.BLUE: 1>

>>> EnumWithAttrs.BLUE.a
'c'

1開示:私はPython stdlibEnumenum34バックポート、およびAdvanced Enumeration(aenum ライブラリの作成者です。

2 は、メタクラスベースaenumもサポートします。NamedConstantsNamedTuples

于 2013-10-10T15:44:59.573 に答える
30

Python 3の場合:

class Status(Enum):
    READY = "ready", "I'm ready to do whatever is needed"
    ERROR = "error", "Something went wrong here"

    def __new__(cls, *args, **kwds):
        obj = object.__new__(cls)
        obj._value_ = args[0]
        return obj

    # ignore the first param since it's already set by __new__
    def __init__(self, _: str, description: str = None):
        self._description_ = description

    def __str__(self):
        return self.value

    # this makes sure that the description is read-only
    @property
    def description(self):
        return self._description_

また、タイプごとに標準の列挙型またはファクトリとして使用できます。

print(Status.READY)
# ready
print(Status.READY.description)
# I'm ready to do whatever is needed
print(Status("ready")) # this does not create a new object
# ready
于 2019-02-17T10:08:37.910 に答える
27

Python 3.4と優れたenumモジュールが追加される前は、 namedtupleを使用することをお勧めします。

from collections import namedtuple

Item = namedtuple('abitem', ['a', 'b'])

class Items:
    GREEN = Item('a', 'b')
    BLUE = Item('c', 'd')

最近、サポートされているバージョンのPythonにはが含まれてenumいるので、そのモジュールを使用してください。これにより、各列挙値の生成方法をより細かく制御できます。

各アイテムに値のタプルを指定すると、これらは__init__個別の(位置)引数としてメソッドに渡されます。これにより、列挙値に追加の属性を設定できます。

from enum import Enum

class Items(Enum):
    GREEN = ('a', 'b')
    BLUE = ('c', 'd')

    def __init__(self, a, b):
        self.a = a
        self.b = b

これにより、値が各名前に割り当てられたタプルである列挙型エントリと、2つの属性aおよびb:が生成されます。

>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items(('a', 'b'))
<Items.GREEN: ('a', 'b')>

同じタプルを再度渡すことで、各列挙値を検索できることに注意してください。

最初の項目が各列挙型エントリの値を表す必要がある場合は、__new__メソッドを使用して以下を設定し_value_ます。

from enum import Enum

class Items(Enum):
    GREEN = ('a', 'b')
    BLUE = ('c', 'd')

    def __new__(cls, a, b):
        entry = object.__new__(cls) 
        entry.a = entry._value_ = a  # set the value, and the extra attribute
        entry.b = b
        return entry

    def __repr__(self):
        return f'<{type(self).__name__}.{self.name}: ({self.a!r}, {self.b!r})>'

カスタムも追加しました。__repr__デフォルトには。のみが含まれますself._value_。これで、各エントリの値はタプルの最初の項目によって定義され、列挙型エントリを検索するために使用できます。

>>> Items.GREEN, Items.BLUE
(<Items.GREEN: ('a', 'b')>, <Items.BLUE: ('c', 'd')>)
>>> Items.BLUE.a
'c'
>>> Items.BLUE.b
'd'
>>> Items('a')
<Items.GREEN: ('a', 'b')>

その他のオプションについては、ドキュメントのvs.に関するセクションを__init____new__参照してください。

于 2012-10-01T19:58:15.713 に答える
16

これは、他のアプローチよりも単純だと思うが、最も柔軟性のある別のアプローチです。

from collections import namedtuple
from enum import Enum

class Status(namedtuple('Status', 'name description'), Enum):
    READY = 'ready', 'I am ready to do whatever is needed'
    ERROR = 'error', 'Something went wrong here'

    def __str__(self) -> str:
        return self.name

期待どおりに動作します:

print(Status.READY)
print(repr(Status.READY))
print(Status.READY.description)
print(Status.READY.value)

プリント:

ready
<Status.READY: Status(name='ready', description='I am ready to do whatever is needed')>
I am ready to do whatever is needed
Status(name='ready', description='I am ready to do whatever is needed')

あなたはnamedtuple Enumの最高のものを手に入れます。

于 2020-06-26T18:50:12.370 に答える
2

小さな列挙型の場合、@ propertyが機能する可能性があります:

class WikiCfpEntry(Enum):
    '''
    possible supported storage modes
    '''
    EVENT = "Event"      
    SERIES = "Series"
    
    @property
    def urlPrefix(self):
        baseUrl="http://www.wikicfp.com/cfp"
        if self==WikiCfpEntry.EVENT:
            url= f"{baseUrl}/servlet/event.showcfp?eventid="
        elif self==WikiCfpEntry.SERIES:
            url= f"{baseUrl}/program?id="
        return url
于 2021-07-25T17:04:43.233 に答える
1

他のいくつかの回答に触発されて、他のアプローチのいくつかの欠点を克服し、可能な限り「透過的に」列挙型に追加のフィールドを含める方法を見つけました。追加のフィールドがない場合と同じようにすべてが機能します。

列挙型はタプルと同じように不変であり、列挙型の値は追加フィールドがない場合と同じであり、通常の列挙型と同じように機能しauto()、値で列挙型を選択すると機能します。

import enum

# Common base class for all enums you want to create with additional fields (you only need this once)
class EnumFI(enum.Enum):

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls._values = []

    def __new__(cls, *args, **kwargs):
        value = args[0]
        if isinstance(value, enum.auto):
            if value.value == enum._auto_null:
                value.value = cls._generate_next_value_(None, 1, len(cls.__members__), cls._values[:])  # Note: This just passes None for the key, which is generally okay
            value = value.value
            args = (value,) + args[1:]
        cls._values.append(value)
        instance = cls._member_type_.__new__(cls, *args, **kwargs)
        instance._value_ = value
        return instance

    def __format__(self, format_spec):
        return str.__format__(str(self), format_spec)

次に、コード内のどこでも実行できます。

from enum import auto
from collections import namedtuple

class Color(namedtuple('ColorTuple', 'id r g b'), EnumFI):
    GREEN = auto(), 0, 255, 0
    BLUE = auto(), 0, 0, 255

出力例:

In[4]: Color.GREEN
Out[4]: <Color.GREEN: 1>

In[5]: Color.GREEN.value
Out[5]: 1

In[6]: Color.GREEN.r
Out[6]: 0

In[7]: Color.GREEN.g
Out[7]: 255

In[8]: Color.GREEN.b
Out[8]: 0

In[9]: Color.GREEN.r = 8
Traceback (most recent call last):
  File "/home/phil/anaconda3/envs/dl/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3326, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-9-914a059d9d3b>", line 1, in <module>
    Color.GREEN.r = 8
AttributeError: can't set attribute

In[10]: Color(2)
Out[10]: <Color.BLUE: 2>

In[11]: Color['BLUE']
Out[11]: <Color.BLUE: 2>
于 2021-06-03T14:55:45.550 に答える
1

属性のキーワードベースの初期化では、data-enumを試してみてください。これは、この例を含め、場合によってはよりクリーンな構文を持つenumのより軽量な実装です。

from data_enum import DataEnum

class Item(DataEnum):
    data_attribute_names = ('a', 'b')

Item.GREEN = Item(a='a', b='b')
Item.BLUE = Item(a='c', b='d')

私はdata-enumの作成者であり、このユースケースに対処するために特別に作成したことに注意してください。

于 2021-09-01T15:05:47.340 に答える