You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Decimal子类自定义__str__在f-string中不生效的问题排查与解决

解决Decimal子类自定义__str__在f-string中不生效的问题

问题重现

你编写了Decimal的子类Money来封装金额,自定义__str__实现带符号的货币格式,但f-string场景下未调用该方法:

from decimal import Decimal

class Money(Decimal):
    CURRENCY = "€"

    def __new__(cls, number):
        return super().__new__(cls, Decimal(number).quantize(Decimal("0.01")))

    def __str__(self):
        return f"{self:+}{self.CURRENCY}"

m = Money(10)
print("Test 1 - str():", str(m))
print("Test 2 - print():", m)
print(f"Test 3 - f-string: {m}")
print("Test 4 - f-string str():", f"{str(m)}")

运行结果:

Test 1 - str(): +10.00€
Test 2 - print(): +10.00€
Test 3 - f-string: 10.00 # 此处未调用自定义__str__
Test 4 - f-string str(): +10.00€

原因分析

核心差异在于不同场景触发的底层方法不同:

  • str(m)和print(m)直接调用子类重写的__str__,因此能得到预期格式。
  • f-string的{m}等价于format(m, ''),即调用对象的__format__('')方法。而Decimal类自带的__format__并未遵循Python默认的object.__format__逻辑(默认会委托给__str__),而是直接基于Decimal内部数值实现格式化,完全绕过了子类重写的__str__。

解决方案

在Money类中重写__format__方法,让无格式说明符时调用自定义的__str__,有格式需求时仍复用父类的格式化逻辑:

from decimal import Decimal

class Money(Decimal):
    CURRENCY = "€"

    def __new__(cls, number):
        return super().__new__(cls, Decimal(number).quantize(Decimal("0.01")))

    def __str__(self):
        return f"{self:+}{self.CURRENCY}"

    def __format__(self, format_spec):
        # 无格式说明符时,使用自定义__str__的结果
        if not format_spec:
            return str(self)
        # 有格式说明符时,调用父类的__format__保持原有逻辑
        return super().__format__(format_spec)

m = Money(10)
print(f"Test 3 - f-string: {m}")  # 现在输出 +10.00€

机制详解

  1. __str__ vs __format__:
    • __str__用于生成对象的“友好字符串表示”,直接被str()和print()调用。
    • __format__用于格式化字符串,支持自定义格式说明符,是f-string、format()函数的底层调用方法。
  2. 继承与父类方法行为:
    • 普通Python类继承自object,object.__format__默认会调用__str__,因此子类重写__str__后,f-string会自动生效。
    • 但Decimal类重写了__format__,实现了适配自身数值特性的格式化逻辑,因此子类必须显式重写__format__才能介入格式化流程。

内容的提问来源于stack exchange,提问作者Antoine Gallix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 08:43:21