Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
769 views
in Technique[技术] by (71.8m points)

python - Create an abstract Enum class

I'm trying to create an abstract enum (Flag actually) with an abstract method. My final goal is to be able to create a string representation of compound enums, based on the basic enums I defined. I'm able to get this functionality without making the class abstract.

This is the basic Flag class and an example implementation:

from enum import auto, Flag

class TranslateableFlag(Flag):
    @classmethod
    def base(cls):
        pass

    def translate(self):
        base = self.base()
        if self in base:
            return base[self]
        else:
            ret = []
            for basic in base:
                if basic in self:
                    ret.append(base[basic])
            return " | ".join(ret)

class Students(TranslateableFlag):
    ALICE = auto()
    BOB = auto()
    CHARLIE = auto()
    ALL = ALICE | BOB | CHARLIE

    @classmethod
    def base(cls):
        return {Students.ALICE: "Alice", Students.BOB: "Bob",
                Students.CHARLIE: "Charlie"}

An example usage is:

((Students.ALICE | Students.BOB).translate())
[Out]: 'Alice | Bob'

Switching to TranslateableFlag(Flag, ABC) fails due to MetaClass conflicts. (I didn't understand this post - Abstract Enum Class using ABCMeta and EnumMeta, so I'm not sure if it's answering my question).

I would like get a functionality like this somehow:

@abstractclassmethod
@classmethod
    def base(cls):
        pass

Is it possible to achieve this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's how to adapt the accepted answer to the question Abstract Enum Class using ABCMeta and EnumMeta to create the kind of abstract Enum class you want:

from abc import abstractmethod, ABC, ABCMeta
from enum import auto, Flag, EnumMeta


class ABCEnumMeta(ABCMeta, EnumMeta):

    def __new__(mcls, *args, **kw):
        abstract_enum_cls = super().__new__(mcls, *args, **kw)
        try:  # Handle existence of undefined abstract methods.
            absmethods = list(abstract_enum_cls.__abstractmethods__)
            absmethods_str = ', '.join(f'{method!r}' for method in absmethods)
            plural = 's' if len(absmethods) > 1 else ''
            raise TypeError(
                f"cannot instantiate abstract class {abstract_enum_cls.__name__!r}"
                f" with abstract method{plural} {absmethods_str}")
        except AttributeError:
            pass
        return abstract_enum_cls


class TranslateableFlag(Flag, metaclass=ABCEnumMeta):

    @classmethod
    @abstractmethod
    def base(cls):
        pass

    def translate(self):
        base = self.base()
        if self in base:
            return base[self]
        else:
            ret = []
            for basic in base:
                if basic in self:
                    ret.append(base[basic])
            return " | ".join(ret)


class Students1(TranslateableFlag):
    ALICE = auto()
    BOB = auto()
    CHARLIE = auto()
    ALL = ALICE | BOB | CHARLIE

    @classmethod
    def base(cls):
        return {Students1.ALICE: "Alice", Students1.BOB: "Bob",
                Students1.CHARLIE: "Charlie"}


class Students2(TranslateableFlag):
    ALICE = auto()
    BOB = auto()
    CHARLIE = auto()
    ALL = ALICE | BOB | CHARLIE

# Abstract method not defined - should raise TypeError.
#    @classmethod
#    def base(cls):
#        ...

Result:

Traceback (most recent call last):
  ...
TypeError: cannot instantiate abstract class 'TranslateableFlag' with abstract method 'base'

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...