Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How does python3.11's StrEnum's MRO work differently for __str__ and __repr__?

Python3.11 introduced StrEnum and IntEnum which inherit str or int respectively, and also inherit ReprEnum, which in turn inherits Enum.

ReprEnum‘s implementation is actually empty.

>>> print(inspect.getsource(ReprEnum))
class ReprEnum(Enum):
    """
    Only changes the repr(), leaving str() and format() to the mixed-in type.
    """

If I create a StrEnum and check the MRO, I can see that str comes first.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class Strings(StrEnum):
    A = "a"
>>> Strings.__mro__
(<enum 'Strings'>, <enum 'StrEnum'>, <class 'str'>, <enum 'ReprEnum'>, <enum 'Enum'>, <class 'object'>)

Both str and Enum define a __str__ and a __repr__

>>> str.__repr__
<slot wrapper '__repr__' of 'str' objects>
>>> str.__str__
<slot wrapper '__str__' of 'str' objects>
>>> Enum.__repr__
<function Enum.__repr__ at 0x7ffff69f72e0>
>>> Enum.__str__
<function Enum.__str__ at 0x7ffff69f7380>

How then does __repr__ get inherited from Enum and __str__ get inherited from str?

>Solution :

The __repr__ method comes the normal way, inherited from Enum (via StrEnum)

>>> Strings.__repr__ is StrEnum.__repr__ is Enum.__repr__
True

For the __str__ method, the metaclass EnumType checks for the presence of ReprEnum and "hoists up" the str and format handling of the mixed-in data type into the class namespace at class definition time here:

class EnumType(type):

    ...

    def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **kwds):

        ...

        # Also, special handling for ReprEnum
        if ReprEnum is not None and ReprEnum in bases:
            if member_type is object:
                raise TypeError(
                        'ReprEnum subclasses must be mixed with a data type (i.e.'
                        ' int, str, float, etc.)'
                        )
            if '__format__' not in classdict:
                enum_class.__format__ = member_type.__format__
                classdict['__format__'] = enum_class.__format__
            if '__str__' not in classdict:
                method = member_type.__str__
                if method is object.__str__:
                    # if member_type does not define __str__, object.__str__ will use
                    # its __repr__ instead, so we'll also use its __repr__
                    method = member_type.__repr__
                enum_class.__str__ = method
                classdict['__str__'] = enum_class.__str__

        ...

Now that a Strings.__str__ method may be found directly in the class namespace, the MRO needn’t be traversed.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading