自定义 __repr__ 作为 class 方法,用于从 Enum 派生的 class

custom __repr__ as a class method for a class derived from Enum

我有一个 class 派生自 enum.Enum。 现在 repr in enum.Enum 指的是 enum.Enum 的成员而不是整个 class.

例如

from enum import Enum
class endpoints(Enum):
""" shop """
    shop = 'shop'
    countries = 'countries'
    policies = 'policies'
    
print(endpoints)

结果

<enum 'endpoints'>

我试过的

from enum import Enum
class endpoints(Enum):
    shop = 'shop'
    countries = 'countries'
    policies = 'policies/{object_id}'
    @classmethod
    def __repr__(cls):
        return  '\n'.join([str(member.name) + ':' + (member.value) for member in cls.__members__])

print(endpoint)

        

结果

<enum 'endpoints'>

这表明 repr 实际上是 endpoints.member。repr 我需要的是端点。repr?

我知道这可以通过一个 metaclass here 来实现,但是由于 Enum 本身有一个 metaclass,我不能从另一个 meta[=] inherit/assign 52=].

没有修改 enum.Enum 我怎样才能实现我的 objective。

期望的输出如下。

print(endpoints)
shop : shop
countries : countries 
policies : policies/{object_id}

__repr__ 仅在 class 实例上调用,如 endpoints('shop') 而不是在 class 本身上调用。

或者您可以使用自己的 class 方法而不是 __repr__,例如 enum_members(cls),然后您可以在 class 本身而不是实例上调用这个自己的方法。

此外,您必须执行 print(repr(obj)) 而不是 print(obj) 才能使用 __repr__ 方法。如果您只想 print(obj) 然后创建 __str__ 方法而不是 __repr__.

而不是 cls.__members__ 使用 list(cls) 枚举所有枚举成员。

Try it online!

from enum import Enum
class endpoints(Enum):
    shop = 'shop'
    countries = 'countries'
    policies = 'policies/{object_id}'
    @classmethod
    def __repr__(cls):
        return '\n'.join([str(member.name) + ':' + (member.value) for member in list(cls)])

print(repr(endpoints('shop')))

输出:

shop:shop
countries:countries
policies:policies/{object_id}

要修改 class 对象的打印方式,就像任何对象一样,您需要修改它的 classes __repr__,即 meta class__repr__,不是简单的用classmethod装饰MyClass.__repr__。在这种情况下,您需要自定义 EnumMeta:

In [1]: from enum import EnumMeta, Enum

In [2]: class CustomEnumMeta(EnumMeta):
   ...:     def __repr__(self):
   ...:         return '\n'.join([f"{name}: {value}" for name, value in self.__members__.items()])
   ...:

In [3]: class Endpoints(Enum, metaclass=CustomEnumMeta):
   ...:     shop = 'shop'
   ...:     countries = 'countries'
   ...:     policies = 'policies'
   ...:

In [4]: Endpoints
Out[4]:
shop: Endpoints.shop
countries: Endpoints.countries
policies: Endpoints.policies

基本上,

but since Enum itself has a metaclass, I cannot inherit/assign from another metaclass.

错了。您可以提供自定义元class ,如果它源自基础的元class就好了,即使您的基础class有一个元class。它必须以这种方式工作,因为所有classes都有一个元class,默认情况下,type.

来自documentation:

3.3.3.3. Determining the appropriate metaclass

  • if no bases and no explicit metaclass are given, then type() is used;

  • if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass;

  • if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used.

The most derived metaclass is selected from the explicitly specified metaclass (if any) and the metaclasses (i.e. type(cls)) of all specified base classes. The most derived metaclass is one which is a subtype of all of these candidate metaclasses.

添加了重点。所以在这个单继承的简单例子中,由于 CustomEnumMetaCustomEnumMetaEnumMeta 之间最派生的 metaclass,所以它被用作 metaclass .