自定义 __repr__ 作为从 Enum 派生的类的类方法
Posted
技术标签:
【中文标题】自定义 __repr__ 作为从 Enum 派生的类的类方法【英文标题】:custom __repr__ as a class method for a class derived from Enum 【发布时间】:2021-06-17 18:56:31 【问题描述】:我有一个派生自 enum.Enum 的类。 现在 enum.Enum 中的 repr 指的是 enum.Enum 的成员,而不是整个类。
举例
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?
我知道这可以通过元类here 来实现,但由于 Enum 本身有一个元类,我不能从另一个元类继承/分配。
没有修改 enum.Enum 我该如何实现我的目标。
想要的输出如下。
print(endpoints)
shop : shop
countries : countries
policies : policies/object_id
【问题讨论】:
您的minimal reproducible example 有语法错误。无法复制。 @wwii 修复了错误 【参考方案1】:要修改类对象的打印方式,就像任何对象一样,您需要修改它的类__repr__
,即元类__repr__
,而不是简单地用MyClass.__repr__
装饰classmethod
。在这种情况下,您需要自定义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
基本上,
但由于 Enum 本身有一个元类,我不能从另一个元类继承/分配。
错了。您可以提供自定义元类如果它派生自基类的元类就好了,即使您的基类有元类。它必须以这种方式工作,因为所有类都有一个元类,默认情况下,type
。
来自documentation:
3.3.3.3。确定合适的元类
如果没有给出基数和显式元类,则使用
type()
;如果给出了一个显式的元类并且它不是
type()
的实例,那么它直接作为元类使用;如果
type()
的实例作为显式元类给出,或者定义了基类,则使用最派生的元类。从显式指定的元类(如果有)和所有的元类(即
type(cls)
)中选择派生最多的元类 指定的基类。派生最多的元类是一个 所有这些候选元类的子类型。
添加了重点。所以在这个简单的单继承案例中,由于CustomEnumMeta
是CustomEnumMeta
和EnumMeta
之间派生最多的元类,那么它就被用作元类。
【讨论】:
这是我一直在寻找的答案。你是对的就是说我错了。当我尝试使用自定义元类的解决方案时,我收到一个语法错误,说明我的元类和枚举元类之间存在冲突,因为我的元类不完整并且无法创建对象,从原始元类派生是一个更明智的解决方案。 【参考方案2】:__repr__
仅在类实例上调用,例如 endpoints('shop')
,而不是在类本身上。
您可以使用自己的类方法(如enum_members(cls)
)代替__repr__
,然后您可以在类本身而不是实例上调用这个自己的方法。
您还必须使用print(repr(obj))
而不仅仅是print(obj)
才能使用__repr__
方法。如果您只想print(obj)
,则创建__str__
方法而不是__repr__
。
使用list(cls)
代替cls.__members__
枚举所有枚举成员。
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
【讨论】:
以上是关于自定义 __repr__ 作为从 Enum 派生的类的类方法的主要内容,如果未能解决你的问题,请参考以下文章
自定义输出内容 __str__() 和 __repr__() 以及__format__() 的使用
如何直接使用 `str.format` 作为 `__repr__`?
Python进阶-----通过类的内置方法__str__和__repr__自定制输出(打印)对象时的字符串信息