惊讶于 f'{enum}' != string(enum) 对于具有字符串混合的枚举,这是怎么回事?

Suprised that f'{enum}' != str(enum) for Enums that have a str mixin, What's going on?

下面,为什么 str.__str__(似乎)优先于“更具体”的 Mixin.__str__Enum.__str__ 对于 Mixin.BEE

尽管 Python docs on f-strings 说:

A general convention is that an empty format specification produces the same result as if you had called str() on the value. A non-empty format specification typically modifies the result.

引擎盖下发生了什么?

def format_vs_str(val):
    formatted, stred = f'{val}', str(val)
    if formatted != stred:
        raise ValueError(f'{repr(formatted)} != {repr(stred)}')
    return True


format_vs_str(1)  # True

format_vs_str('adsfa')  # True

Normal = Enum('Normal', {'BEE': 'BEE', 'C': 'CAT'})
format_vs_str(Normal.BEE) #  True

Mixin = Enum('Mixin', {'BEE': 'BEE', 'C': 'CAT'}, type=str)
format_vs_str(Mixin.BEE)  # ValueError: 'BEE' != 'Mixin.BEE'

Mixin.__str__(Mixin.BEE)  # 'Mixin.BEE'
Enum.__str__(Mixin.BEE)  # 'Mixin.BEE'
str.__str__(Mixin.BEE)  # 'BEE'

更多怪事:

class Foo(str):
    def __str__(self):
        return 'my own str'

foo = Foo()

str(foo)  # 'my own str'
f'{foo}'  # 'my own str'
str.__str__(foo)  # '' ???
正在使用

__format__ 而不是 __str__。在代码中:

enum = Mixin.BEE

[f'{enum}', str(enum)]                 # ['BEE', 'Mixin.BEE']

# underneath, will call dunders:
[enum.__format__(''), enum.__str__()]  # ['BEE', 'Mixin.BEE']

# "proof", see: https://docs.python.org/3/library/dis.html#opcode-FORMAT_VALUE
import dis
dis.dis("f'{Mixin.BEE}'")
#  1           0 LOAD_NAME                0 (Mixin)
#              2 LOAD_ATTR                1 (BEE)
#              4 FORMAT_VALUE             0
#              6 RETURN_VALUE