为何Python的f-string与str()转换对子类的执行结果不一致?
问题描述
我们在Decimal的子类中重写__str__方法后,用两种方式调用出现结果差异:
from decimal import Decimal class D(Decimal): def __str__(self): return super().normalize().__str__() num = D('1.0') print(f"{num}") print(f"{str(num)}")
输出结果:
1.0 1
预期两者都输出1,但第一个print似乎调用了Decimal.__str__而非D.__str__,请问该现象的原因及解决方法?
原因分析
这是因为f-string在格式化对象时,对于部分由C扩展实现的内置类型(比如Decimal),会绕过子类的__str__方法,直接调用父类的原生实现。
Python的f-string底层会优先尝试调用对象的__format__方法,如果没有自定义实现,对于Decimal这类C扩展类型,会直接走内部的快速格式化逻辑,不会触发子类重写的__str__;而str(num)则是按照正常的方法解析顺序,先查找子类的__str__,找不到才会去父类找,所以能正确执行我们重写的逻辑。
解决方法
重写子类的__format__方法,让f-string格式化时也使用我们自定义的逻辑:
from decimal import Decimal class D(Decimal): def __str__(self): return super().normalize().__str__() def __format__(self, format_spec): # 复用__str__的逻辑,也可根据format_spec做定制化处理 return self.__str__() num = D('1.0') print(f"{num}") print(f"{str(num)}")
此时输出会统一为:
1 1
内容的提问来源于stack exchange,提问作者goweon
相关产品推荐
相关产品推荐

