Python Object-oriented Programming -5 Encapsulation

Young Chen
宅男雜誌
Published in
4 min readFeb 10, 2020

再談封裝

封裝(Encapsulation): 將資料與函數放在一種稱為物件的結構中

定義十分簡潔,事實上在前幾篇的例子中定義一個class也已經實作了封裝的動作。不過有些延伸的議題會產生,有時候設計時需要防止子類別或其他外部類別存取類別的屬性。

其它OOP程式語言如C++、Java,使用關鍵字protected, private, public不同屬性/方法的等級來實現此種可能需求。但在Python中,物件的所有屬性與方法都是public,這意味著防止任何屬性被呼叫是沒有意義的。

ummm…so true

Python中,物件的所有屬性與方法都是public

雖然不能防止,但其實Python中仍有一些方式區別private。慣例上_var作為protected,__var作為private,以下來試驗:

class employee:
def __init__(self, name, sal):
self.name=name
self.__salary=sal
emp = Employee('Young', 500)
emp._name # Young

事實上,加上_並沒有真正保護相關屬性,依然可以存取。但身為遵守慣例的工程師應該要知道:在Python中,_var 慣例上就是private,在物件之外不應修改其值(但做的到)。

其實透過變數命名__var可以類似實現private的方式,讓試圖存取時出現錯誤:

class Employee:
def __init__(self, name, sal):
self.name=name
self.__salary=sal
emp = Employee('Young', 500)
emp.__salary
# AttributeError: 'Employee' object has no attribute '__salary'

雖然觸發了AttributeError,看似不能存取該屬性,實際上是因為觸發了name mangling。name mangling意義在於避免衍生類別/子類別名稱碰撞 (name collisions) ,這樣只是剛好觸發副作用而已。換言之,其實你硬要存取,可以透過_<class_name>__<attribute_name> 存取,即emp._Employee__salary 存取。

總結來說,一般靜態程式語言如Java,C++封裝中擁有的private, protected特性在Python中是介於有跟沒有之間的存在,官方文件如此開示:

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member).

我的專案進度也在有跟沒有之間(握拳

所以,其實private在Python中應該使用_ 就好,並且注意到要自律地別任意存取。雖然沒任何強制的效果,但身為負責的工程師,好好遵循規範吧!如果需要追求類似private效果,或許你可以嘗試__ ,但是如果懂的人,還是有法操作。

--

--

Young Chen
宅男雜誌

曾經是全端工程師,目前在資料科學團隊中主要負責雲端架構相關工作,透過自學正在資料科學領域相關知識耕耘中。mail: chiyoung0307@gmail.com