具有可变数量属性的枚举成员的 Python 元类
Posted
技术标签:
【中文标题】具有可变数量属性的枚举成员的 Python 元类【英文标题】:Python metaclass for Enum members with variable number of attributes 【发布时间】:2021-08-22 18:49:04 【问题描述】:我是 Python 元类的新手,目前正在尝试实现以下目标:
from enum import Enum, EnumMeta
class FlexEnumMeta(EnumMeta):
# see the attempt for the implementation below
...
class FlexEnum(Enum, metaclass=FlexEnumMeta, attrs=('foo', 'bar')):
X = 'abc', 123
Y = 'def', 456
我希望它可以按如下方式工作:
FlexEnum.X.foo
>>> 'abc'
我阅读了 Enum 和 aenum 的部分源代码以试图理解,据我所知,这是 FlexEnumMeta 的代码:
class FlexEnumMeta(EnumMeta):
@classmethod
def __prepare__(metacls, cls, bases, attrs=None, **kwargs):
return
def __new__(metacls, name, bases, clsdict, attrs=None, **kwargs):
# Proper way to get an _EnumDict,
# to be passed to super().__new__
enum_dict = super().__prepare__(name, bases, **kwargs)
# Enumeration class members
members = []
for member_name, values in clsdict.items():
# Copy original clsdict in final class members list
if member_name.startswith('_'):
enum_dict[member_name] = values
continue
# Create correspondance between attributes names and values
value_dict = dict(zip(attrs, values))
members.append((member_name, value_dict))
# Copy custom class members in final class members list
for key, value in members:
enum_dict[key] = value
return super().__new__(metacls, name, bases, enum_dict)
class FlexEnum(Enum, metaclass=FlexEnumMeta, attrs=('foo', 'bar')):
X = 'abc', 123
FlexEnum.X
>>> <FlexEnum.X: 'foo': 'abc', 'bar': 123>
FlexEnum.X.value['foo']
>>> 'abc'
我尝试使用 aenum 的 MultiValue 设置,但我需要将 dict 作为我的属性之一,并且这些属性不可散列。 最后,这对我来说是一种锻炼。
【问题讨论】:
每个成员的属性和值是相同的还是分开的?如果分开,实际值重要吗?是否需要通过foo
或bar
的值来查找成员?
所有成员的属性相同,但值不同。我实际上不需要查找除了姓名以外的任何其他成员,因此 chepner 的答案可能就是我想要的。我想我真的想在不合适也没有必要的地方使用元类。
【参考方案1】:
您只需要定义FlexEnum.__init__
:
import enum
class FlexEnum(enum.Enum):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
X = 'abc', 123
Y = 'def', 456
然后
>>> FlexEnum.X.foo
'abc'
成员本身的值将是元组。如果你想要别的东西,你可以覆盖__new__
。文档中有更多信息,When to use __new__()
vs. __init__()
。
【讨论】:
感谢您的旅游回答,这似乎不合适。尽管如此,是否有办法在元类级别封装这种初始化,例如从这个元类派生的所有类都可以使用其成员的属性作为参数进行初始化?FlexEnum.X.foo
的示例repr 错误,即'abc'
属性,FlexEnum.X.bar
是123
。
@Blckknght 这是示例输出中的错字。类定义本身是正确的。以上是关于具有可变数量属性的枚举成员的 Python 元类的主要内容,如果未能解决你的问题,请参考以下文章