CodeGym /Java Adesua /Python SELF TW /內建方法和屬性

內建方法和屬性

Python SELF TW
等級 15 , 課堂 5
開放

5.1 訪問層級

你應該注意到了構造函數有個奇怪的名字 __init__?未來你會常常遇到這種情況。

在Python中,有不同的訪問層級來控制類別屬性和方法的可見性和安全性。主要的訪問控制機制包括在屬性或方法名前加上一或兩個底線(___)。

使用命名約定

單個底線 _ 用來標示不應在類或模組外使用的屬性和方法。這不是強制的,但這是一個應該遵守的約定,以促進代碼的可讀性和維護性。

雙底線 __ 用來標示真正需要私有和保護的屬性和方法,避免意外或故意的外部訪問。name mangling 機制使它們變得不那麼容易訪問,但仍然可以通過特定名稱訪問。

公共(public)屬性和方法

公共屬性和方法 在代碼的任何位置都可訪問。在Python中,預設所有屬性和方法都是公共的,除非它們的名字以底線開始。


class MyClass:
    def __init__(self):
        self.public_attribute = "I am public"
        
    def public_method(self):
        return "This is a public method"
        

obj = MyClass()
print(obj.public_attribute)  # 可訪問
print(obj.public_method())  # 可訪問

在Python中,透過訪問層級實現了封裝,特別是通過非公共的屬性和方法。

5.2 非公共屬性和方法

受保護的(protected)屬性和方法

受保護的屬性和方法以單個底線_標示,並且設計為在類及其衍生類中使用。這是一個提醒程式員,數據不應在類外使用的約定。


class MyClass:
    def __init__(self):
        self._protected_attribute = "I am protected"
        
    def _protected_method(self):
        return "This is a protected method"
        

obj = MyClass()
print(obj._protected_attribute)  # 可訪問,但不建議
print(obj._protected_method())  # 可訪問,但不建議

私有的(private)屬性和方法

在Python中,私有屬性和方法以兩個底線__標示,專供類內使用,主要目的是隱藏內部實現以及保護數據免受意外更改或外部使用。

為了防止外部代碼直接訪問這些屬性和方法,Python應用了特定的機制,稱為name mangling(名稱混亂)。這個機制會自動修改私有屬性的名稱,為其加上由類名組成的前綴。因此,類MyClass中的私有屬性__private_attribute將轉換為內部名稱_MyClass__private_attribute

這可以防止數據被不小心訪問,同時保留了在類內工作的能力。然而,記住"name mangling"機制並不是絕對的保護——有經驗的程式員可以使用修改過的名稱訪問這些數據。

讓我們來看看實際上是如何工作的:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
        
    def __private_method(self):
        return "This is a private method"
        
    def access_private_method(self):
        return self.__private_method()
         

obj = MyClass()
# print(obj.__private_attribute)  # 錯誤,無法直接訪問
# print(obj.__private_method())  # 錯誤,無法直接訪問
print(obj.access_private_method())  # 可通過類的公共方法訪問

正如例子所示,直接訪問私有屬性或方法會導致錯誤。但Python保留了通過修改後的名稱訪問的可能性。比如,你可以使用"混淆"的名稱訪問私有屬性,如下所示:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
   
obj = MyClass()
print(obj._MyClass__private_attribute)  # 顯示: I am private

雖然可以通過"混淆"的名稱訪問,但這應避免,因為這違反了封裝原則,可能導致代碼不穩定。

要看到Python如何修改屬性的名稱,你可以使用內建函數dir(),它顯示對象的所有可用屬性和方法:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
   
obj = MyClass()
print(dir(obj))  # 顯示對象的所有屬性和方法,包括"混淆"名稱

執行dir()後,你會看到對象的所有屬性和方法列表,包括_MyClass__private_attribute,這證實了"name mangling"的機制。

5.3 自動調用方法

在使用構造函數時,有一個有趣的方面,你可能已經注意到了。方法__init__會自動被調用。

事實上,這種情況還有很多,針對這些情況有很多的方法。例子包括:

方法__str__

如果你的對象有一個__str__方法,它會在試圖將你的對象轉換為字符串時自動被調用,比如在使用print()str()函數時。


class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age
            
    def __str__(self):
        return f"{self.name} is {self.age} years old"
            

cat = Cat("Barsik", 5)
print(cat)  # 顯示: Barsik is 5 years old

方法__len__

如果你的對象有一個__len__方法,則會在試圖確定對象的「長度」時自動被調用——被len()函數使用。例子:


class MyList:
    def __init__(self, items):
        self.items = items
        
    def __len__(self):
        return len(self.items)
        
        
my_list = MyList([1, 2, 3])
print(len(my_list))  # 顯示: 3

這類「內建方法」你還會在將來遇到很多,使用起來非常享受,所以準備好:)

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION