亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

首頁 慕課教程 Python 進階應用教程 Python 進階應用教程 04 Python 類的私有屬性和私有方法

Python 類的私有屬性和私有方法

在 Python 的面向對象編程中,私有屬性是只能在類的實例方法中訪問的屬性,不允許在外界訪問私有屬性。

1. 私有屬性的定義

1.1 定義

在屬性名稱前加上前綴 __,表示該屬性為私有屬性,示例代碼如下:

class Object:
    def method(self):
        self.__private_attribute = 123

在第 3 行,創建一個私有屬性 __private_attribute

1.2 在類外讀取私有屬性

只能在類的實例方法中訪問私有屬性,不允許在類的外部訪問私有屬性,示例代碼如下:

class Person:
    def __init__(self, name):
        self.__name = name
 
tom = Person('tom')
print(tom.__name)
  • 在第 1 行,定義了類 Person
  • 在第 3 行,創建私有屬性 __name
  • 在第 5 行,創建一個實例 tom
  • 在第 6 行,直接訪問實例的屬性 __name

程序運行輸出如下:

Traceback (most recent call last):
  File "attr-get.py", line 6, in <module>
    print(tom.__name)
AttributeError: 'Person' object has no attribute '__name'

程序運行報錯:‘Person’ object has no attribute ‘__name’,表示無法找到屬性 __name’。因此,在類 Person 的外部無法直接讀取實例的私有屬性。

1.3 在類外修改私有屬性

1.2 小節的例子,在類外讀取私有屬性;本節的例子,在類外修改私有屬性。示例代碼如下:

class Person:
    def __init__(self, name):
        self.__name = name
 
    def get_name(self):
        return self.__name

tom = Person('tom')
tom.__name = 'jerry'
print(tom.get_name())
  • 在第 1 行,定義了類 Person
    • 在第 3 行,創建私有屬性 __name
    • 在第 6 行,在類的實例方法 get_name 中,訪問私有屬性 __name
  • 在第 8 行,創建一個實例 tom
    • 在第 9 行,將實例的屬性 __name 修改為 ‘jerry’
    • 在第 10 行,通過實例方法 get_name 讀取私有屬性 __name

程序運行輸出如下:

tom

程序在第 9 行,將實例的私有屬性 __name 修改為 ‘jerry’,但是程序輸出表明:在類的內部,私有屬性 __name 沒有發生變化。因此,在類 Person 的外部無法直接修改實例的私有屬性。

1.4 通過 set/get 方法訪問私有屬性

本節在類的外部訪問私有屬性的方法,代碼如下:

class Person:
    def __init__(self, name):
        self.__name = name
 
    def get_name(self):
        return self.__name
 
    def set_name(self, name):
        self.__name = name

tom = Person('tom')
tom.set_name('jerry')
print(tom.get_name())
  • 在第 1 行,定義了類 Person
    • 在第 3 行,創建私有屬性 __name
    • 在第 5 行,創建方法 get_name,它讀取私有屬性 __name
    • 在第 8 行,創建方法 set_name,它修改私有屬性 __name
  • 在第 11 行,創建一個實例 tom
    • 在第 12 行,通過實例方法 get_name 讀取私有屬性 __name
    • 在第 13 行,通過實例方法 set_name 修改私有屬性 __name

程序輸出結果如下:

jerry

程序輸出表明,通過方法 tom.set_name(‘jerry’) 成功的將私有屬性 __name 設置為 jerry。因此,在類的外部通過 get/set 方法訪問私有屬性。

2. 私有屬性的應用

2.1 概述

數學中的線段擁有 3 個屬性:

  • start,表示開始位置
  • end,表示結束位置
  • length,表示線段的長度,等于 end - start

當修改屬性 start 時,屬性 length 會發生變化;當修改屬性 end 時,屬性 length 也會發生變化;如果修改屬性 start 或者 end 時,忘記修改屬性 length 的話,則會造成邏輯錯誤,示例代碼如下:

class Segment:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.length = self.end - self.start

    def show(self):
        print('start = %d, end = %d, length = %d' % (self.start, self.end, self.length))

segment = Segment(10, 100)
segment.start = 20
segment.show()
  • 在第 2 行,定義構造方法
    • 在第 5 行,使用屬性 start 和 end 計算屬性 length
  • 在第 7 行,定義方法 show,打印屬性 start、end、length
  • 在第 10 行,創建線段 segment,設置 start = 10,end = 100
  • 在第 11 行,將 start 修改為 20
  • 在第 12 行,調用方法 show 打印屬性 start、end、length

程序運行輸出結果如下:

start = 20, end = 100, length = 90

start 修改為 20 后,length 應該等于 80,但是程序輸出表明 length 等于 90。由于 start 修改后,忘記修改 length,造成了這樣的邏輯錯誤。

2.2 使用私有屬性解決問題

為了解決上個小節中的問題,將屬性 start、end、length 設置為私有屬性:

  • 禁止在外界直接訪問這 3 個屬性
  • 只能通過對應的 get/set 方法訪問這 3 個屬性
class Segment:
    def __init__(self, start, end):
        self.__start = start
        self.__end = end
        self.__length = self.__end - self.__start

    def get_start(self):
        return self.__start

    def set_start(self, start):
        self.__start = start
        self.__length = self.__end - self.__start

    def get_end(self):
        return self.__end

    def set_end(self, end):
        self.__end = end
        self.__length = self.__end - self.__start

    def get_length(self):
        return self.__start

    def set_length(self, length):
        self.__length = length

    def show(self):
        print('start = %d, end = %d, length = %d' % (self.__start, self.__end, self.__length))

segment = Segment(10, 100)
segment.set_start(20)
segment.show()

類 Segment,包含 3 個私有屬性,讀寫這些屬性的方法如下:

方法 功能
get_start 讀取屬性 start
set_start 設置屬性 start
get_end 讀取屬性 end
set_end 設置屬性 end
get_length 讀取屬性 length
set_length 設置屬性 length
  • 在第 12 行,在 set_start 方法中,修改屬性 start 時,同時重新計算屬性 length
  • 在第 19 行,在 set_end 方法中,修改屬性 end 時,同時重新計算屬性 length
  • 在 set 方法中,修改 start 和 end 屬性時,同時修改 length 屬性,從而保證了一致性,不會出現上個小節中的邏輯錯誤。

程序運行輸出結果如下:

start = 20, end = 100, length = 80

輸出表明,當屬性 start 修改為 20 后,屬性 length 被修改為 80,避免了上個小節中的錯誤。

3. 私有方法的定義

3.1 定義

在Python 的面向對象編程中, 私有方法是只能在類的實例方法中訪問的方法,不允許在外界訪問私有方法。在方法名稱前加上前綴 __,表示該方法為私有方法,示例代碼如下:

class Object:
    def __private_method(self):
        pass

在第 3 行,定義了一個私有方法 __private_method。

3.2 在類外訪問私有方法

私有方法只能在類的內部被調用,不允許在類的外部訪問。示例代碼如下:

class Object:
    def __private_method(self):
        pass

object = Object()        
object.__private_method()
  • 在第 2 行,定義了一個私有方法 __private_method
  • 在第 5 行,創建一個實例 object
  • 在第 6 行,調用實例的私有方法 __private_method

程序運行輸出如下:

Traceback (most recent call last):
  File "method-error.py", line 6, in <module>
    object.__private_method()
AttributeError: 'Object' object has no attribute '__private_method'

程序運行報錯:‘Object’ object has no attribute ‘__private_method’,表示無法找到方法 __private_method’。因此,在類 Person 的外部無法調用實例的私有方法。

4. 私有方法的應用

4.1 概述

本節完成一個分析文本的程序,文本由多個單詞構成,單詞之間使用空格隔開,單詞的類型如下:

  • 數字,例如 123
  • 字母,例如 abc
  • 操作符,例如 =、+、- 等符號

程序對文本分析后,輸出單詞的類型和值,假設輸入文本為 a = 123,則輸出如下:

alpha    a
operator =
digit    123

程序的思路如下:

  1. 定義方法 parse_string,它將文本分割為多個單詞
  2. 定義方法 parse_word,它判斷并打印單詞的類型
  3. 在方法 parse_string 中調用 parse_word 處理每個單詞

方法 parse_word 用于輔助實現方法 parse_string,不需要被外界訪問,因此將其設定為私有方法。

4.2 使用私有方法解決問題

class Parser:
    def __parse_word(self, word):
        if word.isdigit():
            print('digit    %s' % word)
        elif word.isalpha():
            print('alpha    %s' % word)
        elif word == '=' or word == '+' or word == '-':
            print('operator %s' % word)

    def parse_string(self, string):
        words = string.split(' ')
        for word in words:
            self.__parse_word(word)

parser = Parser()
parser.parse_string('sum = sum + 100')
  • 在第 2 行,定義私有方法 __parse_word,判斷單詞的類型
    • 在第 3 行,通過方法 isdigit 判斷是否為數字
    • 在第 5 行, 通過方法 isalpha 判斷是否為字母
  • 在第 10 行,定義公開方法 parse_string
    • 在第 11 行,使用 split 將文本分割為多個單詞
    • 在第 13 行,循環調用私有方法 __parse_word 處理每個單詞
  • 在第 16 行,在類 Parser 的外部,調用公開方法 parse_string

實現方法 parse_string 是類 Parser 的接口,外界通過這個方法實現分析文本的功能;而方法 __parse_word 是一個輔助方法,它用于實現方法 parse_string,不需要公開給外界調用,因此將它設定為私有方法。

程序運行輸出如下:

alpha    sum
operator =
alpha    sum
operator +
digit    100