简体   繁体   English

具有可变数量属性的枚举成员的 Python 元类

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM