Photo by Dayne Topkin on Unsplash
今天要來介紹Python物件導向設計中的封裝(Encapsulation)概念,主要的目的在保護程式碼中重要的實作細節不被外部知道,以防止外部程式碼直接或不當的存取類別中的屬性(Attribute)及方法(Method),而導致程式邏輯上的錯誤。將複雜的運算邏輯進行封裝(Encapsulation)的好處是,外部程式碼只要透過統一介面來進行存取即可,而無需瞭解其中的運算過程,讓程式碼除了保有存取上的控制外,也易於維護。
今天要來說明的封裝(Encapsulation)重點包含了:
- Python封裝(Encapsulation)
- 私有屬性(Private Attribute)
- 私有方法(Private Method)
一、Python封裝(Encapsulation)
就如同文章開頭所說明的,封裝(Encapsulation)的概念就有點像權限控制,有些屬性(Attribute)或方法(Method)只想於類別內部使用,而不想公開於外部,除了減少程式碼因來源端不適當的使用發生問題外,也可保護其中重要的商業邏輯。
一般情況下,來源端皆可存取類別中公開的屬性(Attribute)及方法(Method),如下範例:
# 部落格類別
class Blog:
# 建構式
def __init__(self):
self.author = "Mike" # 作者屬性
self.titles = [] # 文章標題屬性
# 新增文章
def add_post(self, title):
self.titles.append(title)
blog = Blog()
blog.add_post("Python Programming")
blog.add_post("Learn How to Code")
print("Author: ", blog.author)
print("Blog Titles: ", blog.titles)
執行結果
如果我們要防止來源端存取作者屬性(Attribute)及呼叫新增文章標題方法(Method),則需透過封裝(Encapsulation)的概念來進行設計。接下來就分別說明如何封裝(Encapsulation)類別中的屬性(Attribute)及方法(Method)。
二、私有屬性(Private Attribute)
在類別(Class)中可以進行存取,而外部無法存取的屬性(Attribute)。使用方式就是在私有屬性(Private Attribute)前加上兩個底線(__),如下範例:
# 部落格類別
class Blog:
# 建構式
def __init__(self):
self.__author = "Mike" # 作者屬性
self.__titles = [] # 文章標題屬性
# 新增文章
def __add_post(self, title):
self.__titles.append(title)
blog = Blog()
print(blog.__author)
執行結果
從範例中可以看到,來源端無法存取到類別中的author及titles私有屬性(Private Attribute)。如果是利用Visual Studio Code來開發Python的話,在來源端物件的IntelliSense清單中就選不到私有屬性(Private Attribute),證明成功將其進行封裝(Encapsulation)。
但是Python不像其他物件導向程式語言真的把屬性(Attribute)或方法(Method)變為私有,事實上來源端還是可以存取得到。我們先透過__dict__屬性來查看類別中的屬性(Attribute),如下範例:
但是Python不像其他物件導向程式語言真的把屬性(Attribute)或方法(Method)變為私有,事實上來源端還是可以存取得到。我們先透過__dict__屬性來查看類別中的屬性(Attribute),如下範例:
blog = Blog()
print(blog.__dict__)
執行結果
從執行結果可以看到,Python事實上把加了兩個底線的私有屬性(Private Attribute)重新命名,在前面加上了底線類別名稱,來源端只要透過此名稱還是可以進行存取,如下範例:
blog = Blog()
print(blog._Blog__author) #執行結果為:Mike
所以在類別中的屬性(Attribute)或方法(Method)加上兩個底線(__)主要是告訴來源端此屬性(Attribute)或方法(Method)為私有,避免來源端直接或意外的存取。
三、私有方法(Private Method)
在類別(Class)中可以進行存取,而外部無法存取的方法(Method)。和私有屬性(Private Attribute)作法相同,在私有方法(Private Method)前面加上兩個底線(__),如下範例:
# 部落格類別
class Blog:
# 建構式
def __init__(self):
self.__author = "Mike" # 作者屬性
self.__titles = [] # 文章標題屬性
# 新增文章
def __add_post(self, title):
self.__titles.append(title)
blog = Blog()
blog.__add_post("Python tutorials")
執行結果
範例中的來源端試圖存取私有方法(Private Method)而發生了例外錯誤。另外,和私有屬性(Private Attribute)同樣的原理,當我們在存取私有方法(Private Method)時加上底線類別名稱,還是可以進行呼叫,如下範例:
blog = Blog()
blog._Blog__add_post("Python tutorials") #存取私有方法
print(blog._Blog__titles) #存取私有屬性
執行結果
可以看到我們成功呼叫了私有方法(Private Method),將部落格標題加入了串列(List)中。
四、小結
以上就是Python物件導向設計中的封裝(Encapsulation)觀念,雖然Python無法真的完全阻隔外部程式存取私有屬性(Attribute)及方法(Method),但還是有達到避免直接或意外存取的作用。
如果您喜歡我的文章,請幫我按五下Like(使用Google或Facebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。
如果您喜歡我的文章,請幫我按五下Like(使用Google或Facebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。
雖然用起來效果可能差不多,但是 "private" 應該是 single underscore 開頭的
回覆刪除double underscore 開頭的 (dunder) 的目的是避免 mangling
很有用的教學
回覆刪除