Enumの代わりにEnumMetaをサブクラス化する必要があるのはいつですか?

イーサンファーマン

、この記事ニック・コフランは、にして行った設計上の決定の一部について語っPEP 435Enum種類、そしてどのようにEnumMeta異なる提供するために、サブクラス化することができるEnum体験を。

ただし、Enumメタクラスの使用について私が与えるアドバイス(および私はstdlibの主要な作成者です)は、クラスデコレータや専用のデコレータで必要なことを達成できないなど、本当に正当な理由なしに実行すべきではないということです醜さを隠す機能。そして、私自身の仕事で、私は私が使用して簡単に必要なものは何でもすることができました__new____init__作成するとき、および/または通常のクラス/インスタンスメソッドEnumクラス:

そして、Enumメタクラスのサブクラス化の有無にかかわらず、を掘り下げるときに注意するというこの警告の話があります。

それをすべて考えると、いつ私はEnumMeta自分自身をいじる必要がありますか?

イーサンファーマン

サブクラス化に関してこれまでに見た最良の(そして唯一の)ケースEnumMetaは、次の4つの質問から来ています。

ここでは、動的メンバーのケースについてさらに詳しく説明します。


まず、サブクラス化しないときに必要なコードを見てくださいEnumMeta

stdlibの方法

from enum import Enum
import json

class BaseCountry(Enum):
    def __new__(cls, record):
        member = object.__new__(cls)
        member.country_name = record['name']
        member.code = int(record['country-code'])
        member.abbr = record['alpha-2']
        member._value_ = member.abbr, member.code, member.country_name
        if not hasattr(cls, '_choices'):
            cls._choices = {}
        cls._choices[member.code] = member.country_name
        cls._choices[member.abbr] = member.country_name
        return member                
    def __str__(self):
        return self.country_name

Country = BaseCountry(
        'Country',
        [(rec['alpha-2'], rec) for rec in json.load(open('slim-2.json'))],
        )

aenum方法 1 2

from aenum import Enum, MultiValue
import json

class Country(Enum, init='abbr code country_name', settings=MultiValue):
    _ignore_ = 'country this'  # do not add these names as members
    # create members
    this = vars()
    for country in json.load(open('slim-2.json')):
        this[country['alpha-2']] = (
                country['alpha-2'],
                int(country['country-code']),
                country['name'],
                )
    # have str() print just the country name
    def __str__(self):
        return self.country_name

上記のコードは1回限りの列挙には問題ありませんが、JSONファイルから列挙を作成することが一般的だった場合はどうでしょうか。代わりにこれを実行できるかどうか想像してみてください。

class Country(JSONEnum):
    _init_ = 'abbr code country_name'  # remove if not using aenum
    _file = 'some_file.json'
    _name = 'alpha-2'
    _value = {
            1: ('alpha-2', None),
            2: ('country-code', lambda c: int(c)),
            3: ('name', None),
            }

ご覧のように:

  • _file 使用するjsonファイルの名前です
  • _name 名前に使用する必要があるものへのパスです
  • _valueパスを値3にマッピングする辞書です
  • _init_さまざまな値コンポーネントの属性名を指定します(使用している場合aenum

JSONデータはhttps://github.com/lukes/ISO-3166-Countries-with-Regional-Codesから取得されます-ここに短い抜粋があります:

[{"name": "Afghanistan"、 "alpha-2": "AF"、 "country-code": "004"}、

{"name": "ÅlandIslands"、 "alpha-2": "AX"、 "country-code": "248"}、

{"name": "Albania"、 "alpha-2": "AL"、 "country-code": "008"}、

{"name": "Algeria"、 "alpha-2": "DZ"、 "country-code": "012"}]

ここにあるJSONEnumMetaクラスは:

class JSONEnumMeta(EnumMeta):

    @classmethod
    def __prepare__(metacls, cls, bases, **kwds):
        # return a standard dictionary for the initial processing
        return {}

    def __init__(cls, *args , **kwds):
        super(JSONEnumMeta, cls).__init__(*args)

    def __new__(metacls, cls, bases, clsdict, **kwds):
        import json
        members = []
        missing = [
               name
               for name in ('_file', '_name', '_value')
               if name not in clsdict
               ]
        if len(missing) in (1, 2):
            # all three must be present or absent
            raise TypeError('missing required settings: %r' % (missing, ))
        if not missing:
            # process
            name_spec = clsdict.pop('_name')
            if not isinstance(name_spec, (tuple, list)):
                name_spec = (name_spec, )
            value_spec = clsdict.pop('_value')
            file = clsdict.pop('_file')
            with open(file) as f:
                json_data = json.load(f)
            for data in json_data:
                values = []
                name = data[name_spec[0]]
                for piece in name_spec[1:]:
                    name = name[piece]
                for order, (value_path, func) in sorted(value_spec.items()):
                    if not isinstance(value_path, (list, tuple)):
                        value_path = (value_path, )
                    value = data[value_path[0]]
                    for piece in value_path[1:]:
                        value = value[piece]
                    if func is not None:
                        value = func(value)
                    values.append(value)
                values = tuple(values)
                members.append(
                    (name, values)
                    )
        # get the real EnumDict
        enum_dict = super(JSONEnumMeta, metacls).__prepare__(cls, bases, **kwds)
        # transfer the original dict content, _items first
        items = list(clsdict.items())
        items.sort(key=lambda p: (0 if p[0][0] == '_' else 1, p))
        for name, value in items:
            enum_dict[name] = value
        # add the members
        for name, value in members:
            enum_dict[name] = value
        return super(JSONEnumMeta, metacls).__new__(metacls, cls, bases, enum_dict, **kwds)

# for use with both Python 2/3
JSONEnum = JSONEnumMeta('JsonEnum', (Enum, ), {})

いくつかの注意:

  • JSONEnumMeta.__prepare__ 通常を返します dict

  • EnumMeta.__prepare__のインスタンスを取得するために使用されます_EnumDict-これはインスタンスを取得するための適切な方法です

  • _EnumDict列挙型メンバーを処理するときに必要になる可能性があるため、先頭にアンダースコアが付いたキーが最初に実際に渡されます

  • 列挙型メンバーは、ファイル内と同じ順序です


1開示:私はPython stdlibEnumenum34backport、およびAdvanced Enumeration(aenumライブラリの作成者です。

2これにはが必要aenum 2.0.5+です。

3キーは数値であり、複数の値がEnum必要な場合に複数の値を順番に保持します

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Python:メソッドの代わりにサブクラスを使用する必要があるのはいつですか?

分類Dev

クラスの代わりに構造体を使用する必要があるのはいつですか?

分類Dev

クラスの代わりに構造体を使用する必要があるのはいつですか?

分類Dev

クラスの代わりに構造体を使用する必要があるのはいつですか?

分類Dev

オブジェクトをラップする代わりにプリミティブを使用する必要があるのはいつですか?

分類Dev

Railsでカスタムアクションの代わりに別のコントローラーを作成する必要があるのはいつですか?

分類Dev

抽象クラスの代わりにインターフェースを使用する必要があるのはいつですか?

分類Dev

クラスで関数foo()の代わりにfoo()を使用する必要があるのはなぜですか?

分類Dev

Kotlinの演算子を使用する代わりに、プラス、マイナス、回の関数を使用する必要があるのはいつですか?

分類Dev

オブジェクトの代わりにタプルを使用する必要があるのはいつですか。その逆も同様です。

分類Dev

タスクを待つために、Async.AwaitTaskの代わりにAsync.AwaitIAsyncResultを使用する必要があるのはいつですか?

分類Dev

新しい例外の代わりにThrowableを使用する必要があるのはいつですか?

分類Dev

ミューテックスの代わりにスピンロックを使用する必要があるのはいつですか?

分類Dev

boolの代わりにatomic <bool>を本当に使用する必要があるのはいつですか?

分類Dev

UIButtonの代わりにanyObjectを迅速に使用する必要があるのはいつですか?

分類Dev

AngularでrouterLinkの代わりにhrefを使用する必要があるのはいつですか?

分類Dev

Z3で変数の代わりに関数を使用する必要があるのはいつですか?

分類Dev

getメソッドの代わりにRustVecへの直接アクセスを使用する必要があるのはいつですか?

分類Dev

@Serviceの代わりに@Componentを使用する必要があるのはいつですか?

分類Dev

JSONFieldの代わりにHStoreFieldを使用する必要があるのはいつですか?

分類Dev

items()の代わりにiteritems()を使用する必要があるのはいつですか?

分類Dev

Forループの代わりにマップを使用する必要があるのはいつですか?

分類Dev

Memcachedの代わりにMemcacheを使用する必要があるのはいつですか?

分類Dev

10進数の代わりにdoubleを使用する必要があるのはいつですか?

分類Dev

GL_RGB8の代わりにGL_SRGB8を使用する必要があるのはいつですか?

分類Dev

std :: thread :: spawnの代わりにstd :: thread :: Builderを使用する必要があるのはいつですか?

分類Dev

os.popenの代わりにsubprocess.Popenを使用する必要があるのはいつですか?

分類Dev

React状態変数の代わりにMobXobservableを使用する必要があるのはいつですか?

分類Dev

ドメインの代わりに列挙型を使用する必要があるのはいつですか?

Related 関連記事

  1. 1

    Python:メソッドの代わりにサブクラスを使用する必要があるのはいつですか?

  2. 2

    クラスの代わりに構造体を使用する必要があるのはいつですか?

  3. 3

    クラスの代わりに構造体を使用する必要があるのはいつですか?

  4. 4

    クラスの代わりに構造体を使用する必要があるのはいつですか?

  5. 5

    オブジェクトをラップする代わりにプリミティブを使用する必要があるのはいつですか?

  6. 6

    Railsでカスタムアクションの代わりに別のコントローラーを作成する必要があるのはいつですか?

  7. 7

    抽象クラスの代わりにインターフェースを使用する必要があるのはいつですか?

  8. 8

    クラスで関数foo()の代わりにfoo()を使用する必要があるのはなぜですか?

  9. 9

    Kotlinの演算子を使用する代わりに、プラス、マイナス、回の関数を使用する必要があるのはいつですか?

  10. 10

    オブジェクトの代わりにタプルを使用する必要があるのはいつですか。その逆も同様です。

  11. 11

    タスクを待つために、Async.AwaitTaskの代わりにAsync.AwaitIAsyncResultを使用する必要があるのはいつですか?

  12. 12

    新しい例外の代わりにThrowableを使用する必要があるのはいつですか?

  13. 13

    ミューテックスの代わりにスピンロックを使用する必要があるのはいつですか?

  14. 14

    boolの代わりにatomic <bool>を本当に使用する必要があるのはいつですか?

  15. 15

    UIButtonの代わりにanyObjectを迅速に使用する必要があるのはいつですか?

  16. 16

    AngularでrouterLinkの代わりにhrefを使用する必要があるのはいつですか?

  17. 17

    Z3で変数の代わりに関数を使用する必要があるのはいつですか?

  18. 18

    getメソッドの代わりにRustVecへの直接アクセスを使用する必要があるのはいつですか?

  19. 19

    @Serviceの代わりに@Componentを使用する必要があるのはいつですか?

  20. 20

    JSONFieldの代わりにHStoreFieldを使用する必要があるのはいつですか?

  21. 21

    items()の代わりにiteritems()を使用する必要があるのはいつですか?

  22. 22

    Forループの代わりにマップを使用する必要があるのはいつですか?

  23. 23

    Memcachedの代わりにMemcacheを使用する必要があるのはいつですか?

  24. 24

    10進数の代わりにdoubleを使用する必要があるのはいつですか?

  25. 25

    GL_RGB8の代わりにGL_SRGB8を使用する必要があるのはいつですか?

  26. 26

    std :: thread :: spawnの代わりにstd :: thread :: Builderを使用する必要があるのはいつですか?

  27. 27

    os.popenの代わりにsubprocess.Popenを使用する必要があるのはいつですか?

  28. 28

    React状態変数の代わりにMobXobservableを使用する必要があるのはいつですか?

  29. 29

    ドメインの代わりに列挙型を使用する必要があるのはいつですか?

ホットタグ

アーカイブ