Python中的特殊方法__repr__与__str__的区别与字符串格式化中的应用

reprstr 的核心区别

特性reprstr
目的开发者友好的精确表示终端用户友好的简洁表示
调用场景交互式控制台、调试器、repr()函数print()函数、str()函数
要求应无歧义,最好能重建对象可读性强,简洁明了
输出示例Vector(3, 4)(3, 4)

字符串格式化中的表示形式处理

下面三种格式化方式都会对表达式求值结果调用 repr() 函数:

① 经典格式化(% 运算符)

# %r 会调用对象的 __repr__ 方法
print("Vector: %r" % Vector(3, 4))
# 输出:Vector: Vector(3, 4)

② str.format() 方法

# {!r} 会调用对象的 __repr__ 方法
print("Vector: {!r}".format(Vector(3, 4)))
# 输出:Vector: Vector(3, 4)

③ f-strings(格式化字符串字面值)

# {obj!r} 会调用对象的 __repr__ 方法
v = Vector(3, 4)
print(f"Vector: {v!r}")
# 输出:Vector: Vector(3, 4)

为什么需要 !r 和 %r?

关键原因:精确表示 vs 友好显示
考虑这个例子:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Vector({self.x!r}, {self.y!r})"
    
    def __str__(self):
        return f"({self.x}, {self.y})"

# 创建两个不同的 Vector 对象
v1 = Vector(1, 2)      # 数字参数
v2 = Vector('1', '2')  # 字符串参数

不使用 !r 的问题:

# 不正确的 __repr__ 实现(没有使用 !r)
def __repr__(self):
    return f"Vector({self.x}, {self.y})"

print(repr(v1))  # 输出:Vector(1, 2)
print(repr(v2))  # 输出:Vector(1, 2) ❌ 无法区分数字和字符串!

使用 !r 的正确实现:

# 正确的 __repr__ 实现(使用 !r)
def __repr__(self):
    return f"Vector({self.x!r}, {self.y!r})"

print(repr(v1))  # 输出:Vector(1, 2)   → 数字没有引号
print(repr(v2))  # 输出:Vector('1', '2') → 字符串有引号 ✅

实际应用场景分析

  1. 调试和开发阶段(使用 repr
# 在交互式控制台
>>> v = Vector(3, 4)
>>> v
Vector(3, 4)  # 调用 __repr__

# 调试器显示
# 变量查看窗口显示:Vector(3, 4)
  1. 最终用户展示(使用 str
# 打印给用户看
print(v)  # 输出:(3, 4)  → 简洁友好

# 生成报告
report = f"当前位置: {v}"
print(report)  # 输出:当前位置: (3, 4)
  1. 对象重建(repr 的高级用法)
# 从 __repr__ 输出重建对象
original = Vector(3.5, 4.2)
repr_str = repr(original)  # "Vector(3.5, 4.2)"

# 重建对象(实际应用中需安全验证)
reconstructed = eval(repr_str)  

print(original == reconstructed)  # 需要实现 __eq__ 方法

最佳实践总结

总是实现 repr

使用 {attr!r} 格式确保类型信息不丢失

返回的字符串应能重建对象

按需实现 str

当 print(obj) 需要特殊格式时实现

默认回退到 repr

在格式化中的选择:

# 需要精确表示(调试/日志):
log.debug(f"Received vector: {v!r}")

# 用户友好显示:
print(f"当前位置: {v}")

在自定义类中的实现模板:

class MyClass:
    def __init__(self, *args):
        self.data = args
    
    def __repr__(self):
        # 使用 !r 保持类型信息
        args = ', '.join(repr(arg) for arg in self.data)
        return f"{self.__class__.__name__}({args})"
    
    def __str__(self):
        # 简洁的用户友好表示
        return f"MyObject with {len(self.data)} elements"

理解 reprstr 的区别以及 !r/%r 的作用,是写出专业级 Python 代码的关键。这确保了在开发过程中能看到对象的精确表示,同时又能为用户提供友好的输出。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值