Python 中的 __str__ 与 __repr__

在 Python 中,我们通常使用 str() 函数将任何对象转换为字符串。类似地,我们可以使用 repr() 函数获取对象的字符串表示形式。为了让 str() 和 repr() 产生输出,传递给这些函数的对象必须分别具有 __str__() 方法和 __repr__() 方法的实现。

通常,开发人员对这些方法的功能和用例感到困惑。在本教程中,我们将讨论 str() 函数和 repr() 函数如何工作以及 __str__() 方法和 __repr__() 方法如何影响对象的行为。

Python 中的 str() 函数

str() 函数用于获取对象的字符串表示形式。它将对象作为输入参数并返回其字符串表示形式。例如,我们可以获得浮点数的字符串表示,如下例所示。

myNum = 123.456
myStr = str(myNum)
print("The number is:", myNum)
print("The string is:", myStr)

输出:

The number is: 123.456
The string is: 123.456

类似地,我们可以使用 str() 函数将其他内置数据类型的对象(例如整数、列表、集合、元组等)转换为它们各自的字符串表示形式,如下所示。

myNum = 123
myList = [1, 2, 3, 4, 5]
mySet = {1, 2, 3, 4, 5}
myStr1 = str(myNum)
myStr2 = str(myList)
myStr3 = str(mySet)

print("The number is:", myNum)
print("The string is:", myStr1)
print("The list is:", myList)
print("The string is:", myStr2)
print("The set is:", mySet)
print("The string is:", myStr3)

输出:

The number is: 123
The string is: 123
The list is: [1, 2, 3, 4, 5]
The string is: [1, 2, 3, 4, 5]
The set is: {1, 2, 3, 4, 5}
The string is: {1, 2, 3, 4, 5}

但是,当我们传递使用自定义类定义定义的对象时,输出是不可理解的。为了观察这一点,让我们定义一个具有属性 name 和 age 的 Student 类。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

输出:

The string representation of student object is:
<__main__.Student object at 0x7f6016100070>

在这里,你可以看到函数的输出不像我们转换使用内置数据结构定义的对象时那样容易理解。为什么会这样?

当我们将对象传递给 str() 函数时,将调用类定义中定义的 __str__() 方法。__str__() 方法返回对象的字符串表示。str() 函数然后返回相同的字符串。然而,当我们定义一个自定义类时,并没有 __str__() 方法。因此,str() 函数的输出不是很容易理解。

Python 中的 __str__() 方法

根据我们的要求,我们可以在任何类定义中实现 __str__() 方法。这里唯一的限制是该方法必须返回一个字符串值。例如,我们可以为 Student 类实现 __str__() 方法,如下所示。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name: {} , Age: {}".format(self.name, self.age)
        return myString

在实现 __str__() 方法后,当我们将任何 Student 对象传递给 str() 函数时,它返回的字符串与 __str__() 方法返回的字符串相同。下面的例子展示了它是如何工作的。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name: {} , Age: {}".format(self.name, self.age)
        return myString


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

输出:

The string representation of student object is:
Name: Aditya , Age: 23

你可以以任何方式实现 __str__() 方法。例如,我们可以用另一种方式定义 Student 类的 __str__() 方法,如下所示。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(self.name, self.name, self.age)
        return myString


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

输出:

The string representation of student object is:
Name of student is: Aditya ,Aditya is 23 years old

我们如何实现 __str__() 方法不会影响程序的执行。__str__() 方法的输出仅用于向用户显示输出。

Python 中的 repr() 函数

repr() 函数用于获取任何对象的正式字符串表示。它还将对象作为输入并返回对象的字符串表示形式,如下所示。

myNum = 123
myList = [1, 2, 3, 4, 5]
mySet = {1, 2, 3, 4, 5}
myStr1 = repr(myNum)
myStr2 = repr(myList)
myStr3 = repr(mySet)

print("The number is:", myNum)
print("The string is:", myStr1)
print("The list is:", myList)
print("The string is:", myStr2)
print("The set is:", mySet)
print("The string is:", myStr3)

输出:

The number is: 123
The string is: 123
The list is: [1, 2, 3, 4, 5]
The string is: [1, 2, 3, 4, 5]
The set is: {1, 2, 3, 4, 5}
The string is: {1, 2, 3, 4, 5}

你可以观察到 repr() 函数的输出与 str() 函数的输出几乎相同。但是,两种方法的工作方式完全不同。当我们将任何对象传递给 str() 函数时,__str__() 方法将被调用。另一方面,当我们将任何对象传递给 repr() 函数时,__repr__() 方法将被调用。下面的例子展示了它是如何工作的。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(self.name, self.name, self.age)
        return myString


student1 = Student("Aditya", 23)
myStr1 = str(student1)
myStr2 = repr(student1)
print("The string representation of student object is:")
print(myStr1)
print("The output of repr() is:")
print(myStr2)

输出:

The string representation of student object is:
Name of student is: Aditya ,Aditya is 23 years old
The output of repr() is:
<__main__.Student object at 0x7f6410b78070>

我们在这里用 __str__() 方法定义了 Student 类。如果我们将 Student 类的实例传递给 str() 函数和 repr() 函数,你可以观察到输出是不同的。

str() 函数返回由 __str__() 方法返回的输出,而 repr() 函数返回由 __repr__() 方法返回的输出。如果我们不实现 __str__() 方法,str() 函数也会返回 __repr__() 方法的输出。

Python 中的 __repr__() 方法

__repr__() 方法返回 Python 中对象的规范表示。__repr__() 方法适用于 python 中的所有对象,无论它们是内置类还是自定义类的实例。对于使用自定义类定义的对象,你可以理解 __repr__() 方法的定义,如下所示。

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

这里,self.__module 表示创建当前对象的模块,type(self).__name__ 表示类的名称,hex(id(self)) 表示对象的身份十六进制格式。下面的例子展示了它是如何工作的。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(self.name, self.name, self.age)
        return myString


student1 = Student("Aditya", 23)
myStr = student1.__repr__()
print("The output of __repr__() is:")
print(myStr)

输出:

The output of __repr__() is:
<__main__.Student object at 0x7feb92cc8070>

在这里,你可以看到 __repr__() 方法的输出类似于方法定义中定义的模式。输出显示该对象已在 __main__ 模块中定义并且属于 Student 类。输出还显示了对象的身份。

你应该始终避免覆盖 __repr__() 方法。这是因为 __repr__() 方法用于创建对象的规范字符串表示,借助它我们可以重新实例化相同的对象。

但是,如果我们重写 __repr__() 方法,我们将无法使用 eval() 函数从其字符串表示创建对象。 正如我们已经讨论了 __str__() 方法和 __repr__() 方法的基础知识,让我们列出这两种方法之间的一些区别。

Python 中的 __str__() 与 __repr__()

__str__() 方法返回开发人员可以自定义的对象的用户可读字符串形式。但是,__repr__() 方法返回字符串的规范字符串表示。在某些情况下,__str__() 方法返回的字符串可能与 __repr__() 方法返回的字符串相同。你可以在数字的情况下观察到这一点。

但是,当我们使用自定义类定义获取字符串或对象时,__repr__() 方法返回的字符串与 __str__() 方法返回的字符串不同。下面的例子展示了它是如何工作的。

myStr = "Aditya"
myStr1 = myStr.__repr__()
myStr2 = myStr.__str__()
print("The string is:", myStr)
print("The output from the __repr__() method is:", myStr1)
print("The output from the __str__() method is:", myStr2)

输出:

The string is: Aditya
The output from the __repr__() method is: 'Aditya'
The output from the __str__() method is: Aditya

在这里,你可以观察到 __str__() 方法返回的字符串是 Aditya。另一方面,__repr__() 方法返回规范字符串表示'Aditya'

  • 当我们将 __repr__() 方法返回的字符串传递给 eval() 函数时,它会返回对象。另一方面,当我们将 __str__() 方法返回的字符串传递给 eval() 函数时,它可能返回也可能不返回 python 对象。例如,看下面的例子。
myNum = 1234
myNum1 = myNum.__repr__()
myNum2 = myNum.__str__()
print("The number is:", myNum)
print("The output from the __repr__() method is:", myNum1)
print("The output from the __str__() method is:", myNum2)
output1 = eval(myNum1)
print(output1)
output2 = eval(myNum2)
print(output2)

输出:

The number is: 1234
The output from the __repr__() method is: 1234
The output from the __str__() method is: 1234
1234
1234

在这里,你可以观察到我们可以从使用 __str__() 方法和 __repr__() 方法获得的整数的字符串表示中获得整数对象。现在,看看下面的例子。

myStr = "Aditya"
myStr1 = myStr.__repr__()
myStr2 = myStr.__str__()
print("The string is:", myStr)
print("The output from the __repr__() method is:", myStr1)
print("The output from the __str__() method is:", myStr2)
output1 = eval(myStr1)
print(output1)
output2 = eval(myStr2)
print(output2)

输出:

The string is: Aditya
The output from the __repr__() method is: 'Aditya'
The output from the __str__() method is: Aditya
Aditya
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 9, in <module>
    output2 = eval(myStr2)
  File "<string>", line 1, in <module>
NameError: name 'Aditya' is not defined

你可以看到我们可以从 __repr__() 方法返回的字符串创建一个字符串对象。但是,当我们尝试使用 __str__() 方法返回的字符串创建字符串对象时,程序会遇到 NameError 异常。

  • 你可以覆盖 __str__() 方法并根据你的需要实现它。但是,你不应覆盖 __repr__() 方法。
  • __repr__() 方法主要供开发人员在调试时使用。另一方面,__str__() 方法用于获取用户可以理解的对象的文本表示。
  • 当我们在交互式 python 控制台中键入变量的名称或对象时,调用 __repr__() 方法以产生输出。另一方面,当我们将变量传递给 print() 函数或 str() 函数时,会调用 __str__() 方法。
  • 如果类定义不包含 __str__() 方法,则当我们将对象传递给 str() 函数时,python 解释器会调用 __repr__() 方法。
  • 当我们将容器对象传递给 print() 函数时,无论我们是否在类定义中实现了 __str__() 方法,都会打印容器对象元素的 __repr__() 方法元素与否。

结论

在本文中,我们讨论了 str() 函数、__str__() 方法、repr() 函数和 __repr__() 方法的工作原理。我们还讨论了使用 __str__() 方法和 __repr__() 方法之间的区别。

尽管两种方法的输出相似,但存在明显的差异,使 __repr__() 方法和 __str__() 方法彼此非常不同。当你需要使用字符串表示重新实例化对象时,我建议你使用 __repr__() 方法来获取对象的字符串表示。

另一方面,你应该使用 __str__() 方法来生成人类可读的对象表示,除了通知用户之外,该对象在程序中没有任何用处。