Здравствуйте все!
Первый раз пишу вопрос здесь, возможно его примут.
Решил попробовать сделать свой AutoEnum в Python, избавляющий от необходимости присваивать auto() каждому элементу
from enum import Enum
from enum import auto
class TestAutoEnum(Enum):
FIRST = auto(123)
SECOND = auto()
Получилось вот так:
@auto(start=123)
class From123AutoEnum(Enum): pass
class TestAutoEnum(From123AutoEnum):
FIRST = ()
SECOND = ()
assert TestAutoEnum.FIRST.value == 123
assert TestAutoEnum.SECOND.value == 124
Как можно написать, чтобы то же самое выглядело проще:
@auto(start=123)
class TestAutoEnum(Enum):
FIRST = ()
SECOND = ()
, т.е. чтобы не наследоваться от промежуточного класса
@auto(start=123)
class From123AutoEnum(Enum): pass
?
Моя реализация полностью:
from enum import EnumType, Enum
from typing import Callable
def _new_fn(start: int) -> Callable[[EnumType], Enum]:
def __new__(cls: EnumType) -> Enum:
obj = object.__new__(cls)
obj._value_ = start + len(cls.__members__)
return obj
return __new__
def auto(cls: EnumType|None=None, /, *, start: int=1) -> EnumType:
def wrap(cls: EnumType) -> Callable[[EnumType, int], EnumType]:
def _process_class(cls: EnumType, start_value: int) -> EnumType:
cls.__new__ = _new_fn(start_value)
return cls
return _process_class(cls, start)
if cls is None:
return wrap
return wrap(cls)
@auto
class DefaultAutoEnum(Enum): pass
if __name__ == "__main__":
class TestAutoEnum(DefaultAutoEnum):
FIRST = ()
SECOND = ()
assert TestAutoEnum.FIRST.value == 1
assert TestAutoEnum.SECOND.value == 2
@auto(start=123)
class From123AutoEnum(Enum): pass
class TestAutoEnum(From123AutoEnum):
FIRST = ()
SECOND = ()
assert TestAutoEnum.FIRST.value == 123
assert TestAutoEnum.SECOND.value == 124
Так как декоратор (у меня
@auto
) применяется к
уже созданному объекту,
то элементы перечисления создаются раньше, чем
__new__
из декоратора может повлиять на их создание.
Отсюда предположение, что для задуманного может потребоваться глубокое изменение в Enum или метаклассе EnumType.
Буду признателен за любые мысли по этому поводу, в какую сторону смотреть. Может быть у кого-то уже был опыт в чём-то подобном.
Спасибо.