python3.11的StrEnum的MRO对于__str__和__repr__有何不同?

Abr*_*don 5 python inheritance enums method-resolution-order

Python3.11引入了StrEnumand ,分别IntEnum继承了stror int,并且也继承了ReprEnum,后者又继承了Enum

ReprEnum的实现实际上是空的。

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

如果我创建StrEnum并检查 MRO,我可以看到它str是第一位的。

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

和 都str定义Enuma__str__和 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>
Run Code Online (Sandbox Code Playgroud)

那么如何__repr__get 继承自Enum__str__get 继承自str呢?

wim*_*wim 4

__repr__方法采用正常方式,继承自Enum(via StrEnum)

>>> Strings.__repr__ is StrEnum.__repr__ is Enum.__repr__
True
Run Code Online (Sandbox Code Playgroud)

对于该__str__方法,元类在类定义时EnumType检查是否存在混合数据类型并将其ReprEnum“提升”到类命名空间strformat

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__

        ...
Run Code Online (Sandbox Code Playgroud)

既然Strings.__str__可以直接在类命名空间中找到方法,则无需遍历 MRO。