Вы можете передать базовый тип с помощью методов mixin в функциональный API с аргументом type
:
>>> import enum
>>> value_map = {'a': 1, 'b': 2}
>>> class DoubledEnum:
... @property
... def double_value(self):
... return self.value * 2
...
>>> MyEnum = enum.Enum('MyEnum', value_map, type=DoubledEnum)
>>> MyEnum.a.double_value
2
Для полностью функционального подхода, в котором никогда не используется оператор class
, вы можете создать базовое сочетание с функцией type()
:
DoubledEnum = type('DoubledEnum', (), {'double_value': property(double_value)})
MyEnum = enum.Enum('MyEnum', value_map, type=DoubledEnum)
Вы также можете использовать метакласс enum.EnumMeta()
таким же образом, как Python при создании подкласса class MyEnum(enum.Enum): ...
:
- Создание словаря классов с использованием метакласса
__prepare__
hook
- Вызовите метакласс, передав ему имя класса, базы (
(enum.Enum,)
здесь) и словарь классов, созданный на шаге 1.
Пользовательский подкласс словаря, который используется enum.EnumMeta
, не предназначен для простого повторного использования; он реализует хук __setitem__
для записи метаданных, но не переопределяет метод dict.update()
, поэтому мы должны быть немного осторожнее при использовании словаря value_map
:
import enum
def enum_with_extras(name, value_map, bases=enum.Enum, **extras):
if not isinstance(bases, tuple):
bases = bases,
if not any(issubclass(b, enum.Enum) for b in bases):
bases += enum.Enum,
classdict = enum.EnumMeta.__prepare__(name, bases)
for key, value in {**value_map, **extras}.items():
classdict[key] = value
return enum.EnumMeta(name, bases, classdict)
Затем передайте double_value=property(double_value)
этой функции (вместе с именем enum и словарем value_map
):
>>> def double_value(self):
... return self.value * 2
...
>>> MyEnum = enum_with_extras('MyEnum', value_map, double_value=property(double_value))
>>> MyEnum.a
<MyEnum.a: 1>
>>> MyEnum.a.double_value
2
В противном случае вам разрешено создавать подклассы перечисления без членов (все, что является дескриптором 1039 *, не является членом, поэтому функции, свойства, методы класса и т. Д.), Поэтому вы можете сначала определить перечисление без элементов:
class DoubledEnum(enum.Enum):
@property
def double_value(self):
return self.value * 2
, который является приемлемым базовым классом как для функционального API (например, enum.Enum(..., type=DoubledEnum)
), так и для подхода метакласса, который я кодировал как enum_with_extras()
.