ZetCode

Python __str__ 方法

最后修改于 2025 年 4 月 8 日

这份综合指南探讨了 Python 的 __str__ 方法,这是一个负责对象字符串表示的特殊方法。我们将介绍基本用法、格式化、与 __repr__ 的区别以及示例。

基本定义

__str__ 方法返回对象的字符串表示形式。 它由 str() 内置函数和 print() 函数调用,以人类可读的格式显示对象。

关键特征:它必须返回一个字符串对象,目的是可读,并且应该提供简洁的表示。 它与 __repr__ 不同,后者旨在明确和完整。

基本的 __str__ 实现

这是一个简单的类,实现了 __str__ 以提供自定义的字符串表示形式。 这演示了基本的用法模式。

basic_str.py
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"Person: {self.name}, {self.age} years old"

p = Person("Alice", 30)
print(p)  # Calls __str__ implicitly
print(str(p))  # Explicit call

此示例显示了 __str__ 如何提供可读的字符串格式。 当我们打印对象或调用 str() 时,Python 会调用 __str__ 来获取字符串表示形式。

输出将是 "Person: Alice, 30 years old" (人:爱丽丝,30 岁),这两种情况都表明了 __str__ 如何自定义对象的显示。

__str__ vs __repr__

此示例演示了 __str____repr__ 之间的区别,显示了何时调用每个方法以及它们的预期用途。

str_vs_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})"
    
    def __str__(self):
        return f"({self.x}, {self.y})"

p = Point(3, 4)
print(p)       # Uses __str__: (3, 4)
print(repr(p)) # Uses __repr__: Point(3, 4)

__repr__ 旨在明确 (适合调试),而 __str__ 旨在可读。 print() 函数使用 __str__,而 REPL 使用 __repr__

如果未定义 __str__,则 Python 会回退到 __repr__。 最好同时实现两者,以便在不同的上下文中保持清晰。

使用 __str__ 格式化

__str__ 方法可以包含复杂的格式化,以表格形式显示对象数据,如下所示。

formatting_str.py
class Product:
    def __init__(self, name, price, quantity):
        self.name = name
        self.price = price
        self.quantity = quantity
    
    def __str__(self):
        header = f"{'Name':<15}{'Price':>10}{'Quantity':>12}"
        divider = "-" * 37
        row = f"{self.name:<15}${self.price:>9.2f}{self.quantity:>12}"
        return f"{header}\n{divider}\n{row}"

item = Product("Laptop", 1299.99, 5)
print(item)

此实现创建了一个具有对齐列的格式化表格状输出。 字符串格式化微语言用于控制间距和小数位数,以获得专业的输出效果。

输出将显示标题行、分隔线和整齐对齐的产品数据,演示了 __str__ 如何增强可读性。

继承中的 __str__

使用继承时,可以扩展 __str__ 以包含来自父类和子类的信息,如本例所示。

inheritance_str.py
class Animal:
    def __init__(self, species):
        self.species = species
    
    def __str__(self):
        return f"Species: {self.species}"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__("Canine")
        self.name = name
        self.breed = breed
    
    def __str__(self):
        return f"{super().__str__()}, Name: {self.name}, Breed: {self.breed}"

dog = Dog("Buddy", "Golden Retriever")
print(dog)

子类的 __str__ 使用 super() 调用父类的版本,然后添加自己的信息。 这创建了一个完整的字符串表示形式,结合了类层次结构的两个级别。

输出将是 "Species: Canine, Name: Buddy, Breed: Golden Retriever" (物种:犬科,名称:巴迪,品种:金毛寻回犬),显示了继承链如何构建全面的字符串表示形式。

动态 __str__ 内容

__str__ 可以根据对象的当前状态生成动态内容,如这个基于时间的问候示例所示。

dynamic_str.py
import datetime

class Greeter:
    def __init__(self, name):
        self.name = name
    
    def __str__(self):
        hour = datetime.datetime.now().hour
        if hour < 12:
            time_of_day = "morning"
        elif hour < 18:
            time_of_day = "afternoon"
        else:
            time_of_day = "evening"
        return f"Good {time_of_day}, {self.name}!"

greeting = Greeter("Alice")
print(greeting)  # Changes based on current time

__str__ 实现检查当前时间并生成适当的问候消息。 字符串表示形式会根据调用时间动态变化。

这演示了 __str__ 如何合并运行时信息以创建上下文感知的表示形式,从而使对象更具交互性。

最佳实践

资料来源

作者

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

列出所有 Python 教程