ZetCode

Python __repr__ 方法

最后修改于 2025 年 4 月 8 日

本综合指南探讨了 Python 的 __repr__ 方法,该方法是返回对象的官方字符串表示的特殊方法。

基本定义

__repr__ 方法返回对象的字符串表示。它由 repr() 内置函数调用,并且应该是明确的。

一个好的 __repr__ 应该看起来像一个有效的 Python 表达式,可以重新创建该对象。 它主要用于调试和开发。

基本的 __repr__ 实现

这是一个简单的实现,展示了 __repr__ 如何与基本类一起工作。 该方法应返回一个字符串。

basic_repr.py
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(3, 4)
print(repr(p))  # Output: Point(3, 4)

此示例展示了正确的 __repr__ 实现。 输出看起来像一个有效的 Python 表达式,可以重新创建该对象。

当您直接打印对象或使用 repr() 时,Python 会调用此方法来获取字符串表示。

__repr__ vs __str__

__repr____str__ 的用途不同。 __repr__ 供开发人员使用,而 __str__ 供最终用户使用。

repr_vs_str.py
class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
    
    def __repr__(self):
        return f"Book('{self.title}', '{self.author}')"
    
    def __str__(self):
        return f"{self.title} by {self.author}"

book = Book("Python Crash Course", "Eric Matthes")
print(repr(book))  # Book('Python Crash Course', 'Eric Matthes')
print(str(book))   # Python Crash Course by Eric Matthes

此示例演示了差异。 __repr__ 显示如何重新创建对象,而 __str__ 提供用户友好的字符串。

如果未定义 __str__,Python 将使用 __repr__ 作为后备。

__repr__ 用于调试

一个好的 __repr__ 对于调试非常宝贵,因为它显示了对象的精确状态。 这是一个具有更复杂类的示例。

debugging_repr.py
class ShoppingCart:
    def __init__(self):
        self.items = []
    
    def add_item(self, product, quantity):
        self.items.append((product, quantity))
    
    def __repr__(self):
        items_repr = ', '.join(
            f"('{p}', {q})" for p, q in self.items
        )
        return f"ShoppingCart([{items_repr}])"

cart = ShoppingCart()
cart.add_item("Apple", 3)
cart.add_item("Banana", 5)
print(repr(cart))
# Output: ShoppingCart([('Apple', 3), ('Banana', 5)])

__repr__ 显示购物车的完整状态,包括所有商品及其数量。 它非常适合调试。

该表示形式包括嵌套结构,并保持可以用于重新创建对象的精确格式。

__repr__ 与继承

使用继承时,应在 __repr__ 中包含类名和所有相关属性。 这是正确的方法。

inheritance_repr.py
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"{self.__class__.__name__}({self.name!r}, {self.age})"

class Employee(Person):
    def __init__(self, name, age, employee_id):
        super().__init__(name, age)
        self.employee_id = employee_id
    
    def __repr__(self):
        return (f"{self.__class__.__name__}({self.name!r}, "
                f"{self.age}, {self.employee_id!r})")

emp = Employee("John Doe", 30, "E12345")
print(repr(emp))  # Employee('John Doe', 30, 'E12345')

此示例展示了通过继承实现的正确的 __repr__。 子类包含父类和子类的所有属性。

使用 self.__class__.__name__ 使表示即使在子类化的情况下也能正确工作。

__repr__ 用于自定义容器

对于类似容器的类,__repr__ 应该模仿 Python 的内置容器。 这是一个使用自定义列表类的示例。

container_repr.py
class TaggedList:
    def __init__(self, tag, *items):
        self.tag = tag
        self.items = list(items)
    
    def __repr__(self):
        items_repr = ', '.join(repr(item) for item in self.items)
        return f"{self.__class__.__name__}({self.tag!r}, {items_repr})"
    
    def __str__(self):
        return f"{self.tag}: {', '.join(str(item) for item in self.items)}"

tags = TaggedList("Numbers", 1, 2, 3, 4)
print(repr(tags))  # TaggedList('Numbers', 1, 2, 3, 4)

__repr__ 遵循 Python 的容器类型约定,显示类名和逗号分隔列表中包含的所有元素。

该表示形式可用于完全按照原来的方式重新创建对象,这是 __repr__ 的主要目标。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程