__repr__()
__repr__()
是 Python 中的一个特殊方法(也称为 “dunder” 方法,由 “double underscore” 缩写而来)。当调用一个对象的 repr()
函数或者在控制台中打印一个对象时,这个方法就会被调用。它的目标是返回一个字符串,这个字符串应该是一个合法的 Python 表达式,当通过 eval()
执行时,可以复现这个对象(尽管在实践中,很多时候我们不需要或不可能实现这种复现性)。
__repr__()
的主要目的是为调试和开发提供明确性。这个返回的字符串应该尽量详细,对于开发人员来说应该是明确的。
例如,对于之前的 Person
类:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Person(name={self.name}, age={self.age})"
如果我们创建一个 Person
对象:
p = Person("John", 30)
然后在控制台或代码中尝试打印这个对象:
print(p)
输出将会是:
Person(name=John, age=30)
没有 __repr__()
,我们可能只会得到一个不太有用的字符串,比如 <__main__.Person object at 0x7f065209d0>
,这个字符串只是告诉我们对象的内存地址,而不是它的内容。
还有另一个与此相关的方法,__str__()
,它被 print()
和 str()
调用。如果没有定义 __str__()
, 则会默认回退到 __repr__()
,但 __str__()
更侧重于为用户提供友好的或简洁的字符串表示。
__str__()
__str__()
是 Python 中的一个魔法方法或特殊方法,用于定义一个对象的"informal"或"nicely printable"的字符串表示。当使用 print()
函数或 str()
函数来获取一个对象的字符串表示时,__str__()
方法会被调用。
这个方法的目的是为对象提供一个用户友好的描述,而不像 __repr__()
那样为开发者提供一个严格的描述。换句话说,__str__()
的输出更倾向于为人类读者而设计,而不是为机器或开发者。
下面用一个简单的例子来解释 __str__()
的作用:
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"'{self.title}' by {self.author}"
# 使用上述的Book类
book = Book("1984", "George Orwell")
print(book) # 输出: '1984' by George Orwell
在上述示例中,__str__()
为 Book
对象提供了一个简洁的描述,这样当我们打印 book
对象时,输出的字符串是用户友好的。如果没有实现 __str__()
, Python 通常会回退到使用 __repr__()
(如果已经定义)或者输出一个不太有用的默认字符串,例如 <__main__.Book object at 0x7f065209d0>
。
让我们继续使用上述的 Person
类作为例子。在下面的示例中,我们将同时实现 __repr__()
和 __str__()
方法:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
# 为开发者提供明确性,通常更详细,尽量确保能通过eval()复现对象(尽管并不总是这样)
return f"Person(name='{self.name}', age={self.age})"
def __str__(self):
# 为最终用户提供易读性,更友好、简洁
return f"{self.name}, {self.age} years old"
现在,当我们创建一个 Person
对象并尝试打印它:
p = Person("John", 30)
print(repr(p)) # 使用 __repr__
# 输出: Person(name='John', age=30)
print(p) # 默认使用 __str__
# 输出: John, 30 years old
print(str(p)) # 显式地使用 __str__
# 输出: John, 30 years old
可以看到,当尝试直接打印对象或使用 str()
时,__str__()
被调用,而当使用 repr()
时,__repr__()
被调用。如果类中没有定义 __str__()
, 则直接打印或使用 str()
的调用会回退到 __repr__()
。
当我们谈论 __repr__()
为对象提供一个明确且尽量能够通过 eval()
复现的表示时,意味着该方法返回的字符串,当作为 Python 表达式执行时,应该尽可能地创建一个与原始对象等价或相似的对象。
下面用一个例子来解释这个概念:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
# 使用上述的Point类
p = Point(3, 4)
# 打印对象的repr表示
print(repr(p)) # 输出: Point(3, 4)
# 使用eval函数来执行repr返回的字符串,创建一个新的对象
new_p = eval(repr(p))
# 验证新对象的属性
print(new_p.x) # 输出: 3
print(new_p.y) # 输出: 4
在上述例子中,Point
类的 __repr__()
方法返回一个字符串,这个字符串看起来像是一个调用 Point
构造函数的表达式。当我们用 eval()
函数执行这个字符串时,它实际上创建了一个新的 Point
对象,其属性与原始对象相同。
这种方法使得 __repr__()
产生的输出对于调试和记录非常有价值,因为它提供了创建相同对象的明确“配方”。然而,请注意,并不总是可能或适合确保 __repr__()
的输出可以完全通过 eval()
复现,尤其是当对象的初始化涉及非常复杂的参数或状态时。在这些情况下,__repr__()
的目标仍然是提供尽可能明确和有用的描述。