[英]Python metaclass for Enum members with variable number of attributes
I am new to Python's metaclasses and I am currently trying to achieve the following:我是 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
and I would expect it to work as follow:我希望它可以按如下方式工作:
FlexEnum.X.foo
>>> 'abc'
I read parts of the source code of Enum and aenum to try to understand, and as far as I got was with this code for FlexEnumMeta:我阅读了 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'
I tried using aenum's MultiValue setting, but I need to have a dict as one of my attributes, and those aren't hashable.我尝试使用 aenum 的 MultiValue 设置,但我需要将 dict 作为我的属性之一,而这些属性不可散列。 And in the end, this is kind of an exercise for me.最后,这对我来说是一种锻炼。
All you need is to define FlexEnum.__init__
:您只需要定义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
Then然后
>>> FlexEnum.X.foo
'abc'
The value of the member itself will be the tuple.成员本身的值将是元组。 If you'd like something else, you can override __new__
.如果你想要别的东西,你可以覆盖__new__
。 There is some more information in the documentation, When to use __new__()
vs. __init__()
.文档中有更多信息, 何时使用__new__()
与__init__()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.