__format__方法必须返回字符串而非print输出,其spec参数直接接收格式说明符(如"coord"、"polar"),需手动解析并返回对应格式化字符串,不支持的spec应抛valueerror。

__format__ 方法必须返回字符串,不能只 print
很多人写 __format__ 时习惯在里面用 print() 输出,结果发现 f"{obj:s}" 或 format(obj, "s") 依然显示默认的 <__main__.x object at></__main__.x>。这是因为 __format__ 的职责是**返回格式化后的字符串**,不是执行打印动作。
正确做法是拼接并 return 字符串:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
<pre class="brush:python;toolbar:false;">def __format__(self, spec):
if spec == "coord":
return f"({self.x}, {self.y})"
elif spec == "polar":
r = (self.x**2 + self.y**2)**0.5
return f"r={r:.2f}"
else:
return str(self) # fallback
调用验证:
pt = Point(3, 4)f"{pt:coord}" → "(3, 4)"format(pt, "polar") → "r=5.00"
spec 参数就是 format 字符串中冒号后的部分
__format__ 的第二个参数 spec 直接来自格式说明符,比如 f"{obj:.2f}" 中的 ".2f",f"{obj:!s}" 中的 "!s"(注意:转换标志如 !s、!r 不会传给 spec,它们在调用 __format__ 前就被处理掉了)。
- 如果没写冒号,
spec是空字符串"" -
f"{obj:6d}"→spec == "6d" -
format(obj, ">10")→spec == ">10" - 不支持的
spec应该抛ValueError,而不是静默忽略
常见误判:以为 spec 会自动解析成宽度/对齐/精度——它不会。你得自己解析,比如用正则或字符串方法拆解 "。
和 __str__ / __repr__ 的分工要清晰
__format__ 不是 __str__ 的替代品,而是补充。当格式说明符存在时(即用了冒号),Python 优先调用 __format__;否则才退回到 __str__(或 __repr__)。
所以别这样写:
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
def __format__(self, spec):
return f"Point({self.x}, {self.y})" # 和 __str__ 完全一样 → 冗余
应该让 __format__ 处理“有上下文”的格式需求:
- 单位(
"km"、"mi") - 坐标系(
"cartesian"、"latlon") - 导出格式(
"json"、"csv") - 缩写模式(
"short"vs"long")
而 __str__ 保持简洁可读,__repr__ 保持可调试、可重建。
嵌套格式化时,__format__ 里不要硬编码类型检查
如果你的对象字段本身支持格式化(比如 self.timestamp 是 datetime),别手动转成字符串再拼接:
# ❌ 错误:丢失子对象的格式能力
return f"Time: {self.timestamp.isoformat()}"
<h1>✅ 正确:把 spec 透传下去(如果适用)</h1><p>return f"Time: {self.timestamp:{spec}}" # 让 datetime 自己处理 ".3f" 等</p>
但要注意:不是所有 spec 都适用于子字段。安全做法是提取子字段关心的部分,例如:
if spec.endswith("z"): tz_spec = spec[:-1] or "" return f"{self.dt:{tz_spec}}Z"
直接把原始 spec 全传给子对象,容易触发 ValueError(比如把 "coord" 传给 int)。
真正麻烦的是多层嵌套 + 自定义 spec 解析逻辑,这时候建议用 string.Formatter 子类或提前归一化 spec,而不是在每个 __format__ 里重复写解析代码。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










