Есть ли более простой способ сортировки членов Enum в Python 2? - PullRequest
0 голосов
/ 26 апреля 2018

Я застрял с Python 2.7 для проекта, и у меня есть несколько Enum для интеграции платформы Python (OpenERP) с устаревшей платформой. В Python 2 Enum s не упорядочены по умолчанию:

>>> from enum import Enum
>>> class Color(Enum):
...   RED = 1
...   GREEN = 2
...   BLUE = 3
... 
>>> list(Color)
[<Color.BLUE: 3>, <Color.RED: 1>, <Color.GREEN: 2>]

Если порядок важен, необходимо вручную добавить атрибут _order_ = 'member1, member2, member3'.

>>> class Color(Enum):
...   _order_ = 'RED GREEN BLUE'
...   RED = 1
...   GREEN = 2
...   BLUE = 3
... 
>>> list(Color)
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]

Это прекрасно работает для меньших Enum с, но у меня есть несколько, которые имеют от 10 до 50 имен, и это просто слишком много, чтобы либо набирать, либо читать или сохранять в последовательности, когда имена добавляются / удаляются.

Есть ли другие варианты?

1 Ответ

0 голосов
/ 26 апреля 2018

Начиная с aenum 2.1.2 1 атрибут _order_ может быть функцией; эта функция будет использоваться как key до sort() для размещения Enum членов в правильном порядке:

from aenum import Enum

class Pres(str, Enum):

    _init_ = 'value, precedence'        # footnote 2
    _order_ = lambda m: m.precedence    # footnote 3

    PRESIDENT = 'president', 1
    COUNSELOR_1 = 'first counselor', 2
    COUNSELOR_2 = 'second counselor', 3
    SECRETARY = 'secretary', 4

    def __repr__(self):
        "added so example below is clearer"
        return '<%s.%s>' % (self.__class__.__name__, self.name)

и используется:

>>> list(Pres)
[<Pres.PRESIDENT>, <Pres.COUNSELOR_1>, <Pres.COUNSELOR_2>, <Pres.SECRETARY>]

Хотя я бы не назвал эту следующую версию проще, если вы не можете использовать aenum и не хотите пытаться поддерживать огромный _order_, это возможно с помощью Функционального API

Pres = Enum('Pres', (
        ('PRESIDENT', 'president'),          # comment here
        ('COUNSELOR_1', 'first counselor'),  # more comments here
        ('COUNSELOR_2', 'second counselor'), # you get the idea ;)
        ('SECRETARY', 'secretary'),
        ),
        type=str,
        )

def pres_repr(self):
    "added so example below is clearer"
    return '<%s.%s>' % (self.__class__.__name__, self.name)

Pres.__repr__ = pres_repr

Ужасно, но это работает. Однако, это не будет работать, если необходимо поле precedence.


1 Раскрытие информации: я являюсь автором Python stdlib Enum, enum34 backport и Advanced Enumeration ( aenum) библиотека.

2 _init_ необходимо в этом случае, так как я не хочу, чтобы значение precedence передавалось в конструктор str.

3 ключевой функции будет присвоен один аргумент:

  • нет _init_ -> кортеж (name, value), где значение также может быть кортежем (это было бы в примере выше)
  • с _init_ -> и aenum.NamedTuple с полями name плюс любые поля в _init_ (поэтому name, value и precedence в приведенном выше примере)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...