文章目錄
- 核心概念對比
- 1. 根本目的差異
- 2. 調用場景對比
- 深入解析:何時使用哪種方法
- 場景 1:開發者調試 vs 用戶展示
- 場景 2:技術表示 vs 簡化視圖
- 高級對比:特殊場景處理
- 1. 容器中的對象表示
- 2. 日志記錄的最佳實踐
- 3. 異常信息展示
- 最佳實踐指南
- 1. 何時實現哪個方法?
- 2. 實現原則
- 3. 默認行為與繼承
- 4. 使用 dataclass 簡化
- 常見陷阱與解決方案
- 陷阱 1:只實現一個方法
- 陷阱 2:在 `__str__` 中包含技術細節
- 陷阱 3:忽略安全性
- 實際應用:綜合示例
- 總結:`__repr__` 與 `__str__` 的選擇策略
在 Python 面向對象編程中,
__repr__
和__str__
是兩個最常被混淆的特殊方法。本文將深入解析它們的區別、最佳實踐以及如何在實際開發中正確使用它們,避免常見的陷阱。
核心概念對比
1. 根本目的差異
特性 | __repr__ | __str__ |
---|---|---|
核心目標 | 無歧義的技術表示 | 用戶友好的可讀表示 |
目標用戶 | 開發者 | 最終用戶 |
設計原則 | 明確性、精確性 | 簡潔性、可讀性 |
理想特性 | eval(repr(obj)) == obj | 美觀、易懂的輸出 |
2. 調用場景對比
class Demo:def __repr__(self):return "Demo.__repr__()"def __str__(self):return "Demo.__str__()"obj = Demo()
操作/場景 | 使用的方法 | 輸出示例 |
---|---|---|
print(obj) | __str__ | Demo.__str__() |
str(obj) | __str__ | Demo.__str__() |
repr(obj) | __repr__ | Demo.__repr__() |
交互式環境直接輸入 obj | __repr__ | Demo.__repr__() |
[obj] (在容器中) | __repr__ | [Demo.__repr__()] |
f"{obj}" | __str__ | Demo.__str__() |
logging.debug(obj) | __str__ * | 取決于日志配置 |
*注意:日志模塊默認使用
__str__
,但調試時建議顯式使用repr()
深入解析:何時使用哪種方法
場景 1:開發者調試 vs 用戶展示
class Product:def __init__(self, id, name, price):self.id = idself.name = nameself.price = pricedef __repr__(self):# 開發者需要看到所有關鍵信息return f"Product(id={self.id!r}, name={self.name!r}, price={self.price!r})"def __str__(self):# 用戶只需要看到友好信息return f"{self.name} - ¥{self.price:.2f}"# 使用示例
p = Product("P1001", "無線耳機", 299.99)print(repr(p)) # 開發者調試: Product(id='P1001', name='無線耳機', price=299.99)
print(p) # 用戶展示: 無線耳機 - ¥299.99
場景 2:技術表示 vs 簡化視圖
class NetworkDevice:def __init__(self, ip, mac, status):self.ip = ipself.mac = macself.status = statusdef __repr__(self):# 完整技術細節return (f"NetworkDevice(ip={self.ip!r}, mac={self.mac!r}, "f"status={self.status!r})")def __str__(self):# 簡化狀態顯示status_map = {"up": "? 運行中", "down": "? 已斷開"}return f"設備 {self.ip} [{status_map.get(self.status, '?')}]"# 使用示例
router = NetworkDevice("192.168.1.1", "00:1A:2B:3C:4D:5E", "up")print(repr(router))
# 輸出: NetworkDevice(ip='192.168.1.1', mac='00:1A:2B:3C:4D:5E', status='up')print(router)
# 輸出: 設備 192.168.1.1 [? 運行中]
高級對比:特殊場景處理
1. 容器中的對象表示
class Student:def __init__(self, name, grade):self.name = nameself.grade = gradedef __repr__(self):return f"Student({self.name!r}, {self.grade!r})"def __str__(self):return f"{self.name} ({self.grade})"# 創建學生列表
classroom = [Studen