Python 中的 __str__ 與 __repr__

Aditya Raj 2023年1月30日 2022年5月17日
  1. Python 中的 str() 函式
  2. Python 中的 __str__() 方法
  3. Python 中的 repr() 函式
  4. Python 中的 __repr__() 方法
  5. Python 中的 __str__()__repr__()
  6. まとめ
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}

但是,當我們傳遞使用自定義類定義定義的物件時,輸出是不可理解的。為了觀察這一點,讓我們定義一個具有屬性 nameageStudent 類。

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__() 方法來生成人類可讀的物件表示,除了通知使用者之外,該物件在程式中沒有任何用處。

相關文章 - Python String