下面,为什么str.__str__
(似乎)优先于"更具体的";Mixin.BEE
的Mixin.__str__
和Enum.__str__
?
尽管Python的f-string文档说:
一般约定是,空格式规范产生的结果与对该值调用
str()
的结果相同。非空格式规范通常会修改结果。
到底发生了什么?
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