1

I am new to Python's metaclasses and I am currently trying to achieve the following:

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:

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. And in the end, this is kind of an exercise for me.

2
  • Are the attributes and the value(s) the same for each member, or separate? If separate, is the actual value important? Do you need to look up members by the value of foo or bar? Commented Jun 5, 2021 at 18:49
  • The attributes are the same for all members, but their value vary. I don't actually need to look up members with anything else than their names, so chepner's answer may be what I was looking for. I guess I was really wanting to use metaclasses where it wasn't appropriate nor necessary. Commented Jun 5, 2021 at 22:41

1 Answer 1

1

All you need is to define 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__. There is some more information in the documentation, When to use __new__() vs. __init__().

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks you for tour answer, that seems to ne appropriate. Nonetheless, isn't there a way to encapsulate this initialisation at the metaclass level, such as all classes derived from this metaclass can be initialized with the attributes of their members as parameters ?
The example repr for FlexEnum.X.foo is wrong, that's the 'abc' attribute, FlexEnum.X.bar is 123.
@Blckknght That's a typo in the example output. The class definition itself is correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.