__format__方法必须返回字符串,它只接受format_spec参数并严格要求返回str类型,否则触发TypeError;需解析format_spec字符串、避免print或修改状态,且不继承__str__或__repr__。

__format__ 方法必须返回字符串,不能返回其他类型
Python 的 __format__ 方法本质是为 format() 函数和 f-string 提供支持,它只接受一个 format_spec 参数,并**必须返回 str 类型**。如果返回 int、None 或抛出未捕获的异常,会直接触发 TypeError: non-string returned 或 ValueError。
常见错误是误把格式化逻辑写成「打印」或「修改自身」,比如在方法里调用 print() 或给 self 赋值——这些都不影响 format() 的结果,反而可能掩盖真正的问题。
-
__format__里不要 print / logging / 修改实例状态 - 所有格式化逻辑应聚焦于解析
format_spec并拼接/转换出最终字符串 - 若不支持某类 format spec(如
'x'),建议显式 raiseValueError(f"Unknown format spec '{format_spec}'"),而不是静默 fallback
format_spec 参数是字符串,不是字典或对象
format_spec 是传入 format(obj, spec) 或 f"{obj:spec}" 中冒号后面的全部内容,类型恒为 str,哪怕看起来像数字或关键字。它不会自动解析成整数、布尔值或命名参数——全靠你自己拆解。
例如 f"{obj:05.2f}" 中的 "05.2f" 是一个纯字符串;f"{obj:hex}" 中的 "hex" 也是字符串,不是内置函数 hex 的引用。
立即学习“Python免费学习笔记(深入)”;
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 用
if format_spec == "short":做简单匹配 - 复杂 spec(如带小数点、宽度、填充符)可用正则或
str.split()解析,但注意兼容标准格式语法(参考 PEP 3101) - 若想复用内置类型(如 float/int)的格式规则,可将数据转成对应类型再调
format(),例如format(float(self.value), format_spec)
__format__ 不影响 str() 和 repr(),三者职责分明
__str__ 控制 str(obj) 和 print(obj);__repr__ 控制 repr(obj) 和交互式输出;而 __format__ 只响应 format() 和 f-string 的显式格式说明符。它们互不继承,也不能靠「没定义就 fallback 到 __str__」来省事——没实现 __format__ 就直接报 TypeError。
- 即使
__str__返回"User(id=42)",f"{user:s}"仍会失败,除非你实现了__format__并处理's' - 常见做法:对空
format_spec(即f"{obj}")返回self.__str__();对特定 spec(如'id')返回字段值 - 别在
__format__里调self.__repr__()除非真需要调试格式,否则容易混淆语义
实际例子:支持 'id'、'name' 和空 spec 的 User 类
假设有个 User 类,希望支持 f"{u}"(默认)、f"{u:id}"、f"{u:name}":
class User:
def __init__(self, id_, name):
self.id = id_
self.name = name
def __str__(self):
return f"User({self.id}, {self.name})"
def __format__(self, format_spec):
if not format_spec:
return str(self)
elif format_spec == "id":
return str(self.id)
elif format_spec == "name":
return self.name
else:
raise ValueError(f"Unknown format spec '{format_spec}'")
这样 f"{User(123, 'alice')}" → "User(123, alice)",f"{User(123, 'alice'):name}" → "alice"。注意 format_spec 区分大小写,'NAME' 会报错。
真正容易被忽略的是:当你的类嵌套在容器中(如 f"{users[0]:id}"),或用于 logging 的 %(msg)s 格式化时,__format__ 是否覆盖了预期行为——这时候得检查调用链里是否真走到了你的实现,而不是被中间层拦截或 fallback 到 str()。

















