HOWTO · Python
Python __repr__ 方法
本教程讨论 Python 中的 __repr__ 方法。
本页内容
Python 的 repr() 函数会生成对象的表示形式,便于检查程序状态,尤其适用于交互式会话或调试自查。对于自定义类,Python 会通过该类的 __repr__ 特殊方法获取表示形式。合理的实现能让对象的重要状态一目了然;在可行时,还可以生成类似有效 Python 代码的文本,用于重建对象。
repr() 与 __repr__ 的作用
调用 repr(obj) 会让 Python 通过对象的 __repr__ 实现获取该对象的表示形式。结果是一个字符串。交互式提示符通常会显示表达式的表示形式,因此,实用的 __repr__ 能让实例更容易检查。它不提供序列化功能,也不是脱离对象当前状态的实时视图:调用时,它会格式化当下可用的状态。
如果类没有定义 __repr__,Python 会提供默认表示形式。默认形式可以标识对象的类型和身份,但通常不会说明程序关心的属性值。如果实例原本难以区分或检查,就应定义这个方法。
在类中实现 __repr__
将 __repr__ 定义为实例方法,并返回描述该实例的字符串。在方法签名中,self 是实例参数的惯用名称,并非 Python 关键字。你可以选用其他参数名,但按照 Python 的常见风格使用 self 更合适。运行以下示例:
本节中的代码以及显示的标签或输出仍为英文。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
point = Point(3, 4)
print(repr(point))
Point(3, 4)
这里的方法包含两个坐标,而 repr(point) 会通过 Python 的内置函数请求该对象的表示形式。
__repr__ 必须返回字符串。如果返回其他类型,Python 在尝试获取表示形式时会引发 TypeError。让该方法专注于格式化,不要在其中调用 print,因为像 repr() 这样的调用方需要的是字符串值,以便自行使用或显示。
选择实用的表示形式
提供足够的状态信息,让人能够识别并理解实例。对于简单的值对象,写出类名并展示类似构造函数参数的内容通常很清楚。对于较大的对象,应选择有助于诊断行为的字段,避免倾倒机密、大型集合或重复数据。表示形式应当信息充分,最好也没有歧义。
在可行时,让文本能够用于重建等价实例,例如 Point(3, 4)。这是一个设计目标,不是保证:构造函数可能需要当前无法获取的上下文,或者表示形式可能有意省略部分状态。不要把 __repr__ 当成序列化格式。若需要稳定、带版本信息且可供其他进程解析的存储或交换数据,请使用专门为此设计的格式。
格式化字符串及其他值时,应保留其类型,并让特殊字符清晰可见。例如,对字符串字段使用 repr(),可以区分字符串中嵌入的换行符与表示形式中的实际换行。也要考虑值是否敏感或经常变化;避免在日志或交互式输出中暴露凭据和其他隐私数据。
__repr__ 与 __str__ 的区别
__repr__ 通常用于帮助开发者检查对象,而 __str__ 通常用于提供方便易读的显示内容。这是实用惯例,并不限制谁可以调用这两个方法。例如,程序可以在诊断消息中显示对象的表示形式,开发者也可以在调试时调用 str()。
两个内置函数选择方法的方式不同:repr(obj) 使用 __repr__;如果类提供了 __str__,str(obj) 就会使用它。如果没有定义 __str__,Python 会回退到对象的 __repr__ 行为。当类需要单独面向用户的显示内容时,应实现 __str__;即使两个方法有时返回相似文本,也要让 __repr__ 保持适用于检查对象。
测试表示形式
直接使用 repr(instance) 检查结果,并将其与预期显示的值进行比较。如果定义了 __str__,也要检查 str(instance),因为它可能有意返回不同内容,也可能使用回退行为。运行以下检查:
本节中的代码以及显示的标签或输出仍为英文。
class Status:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"Status({self.name!r})"
def __str__(self):
return self.name
status = Status("ready")
print(repr(status))
print(str(status))
Status('ready')
ready
检查表示形式是否包含预期字段、是否返回字符串,以及是否泄露了应当保密的信息。如果输出有歧义,可以调整格式,或加入更多相关上下文。这些检查有助于在类不断变化时,让表示形式继续发挥作用。