Python 速查手冊

6.6 封裝

封裝 (encapsulation) 是物件導向程式設計 (object-oriented programming) 的重要概念之一,主要目的是封裝類別 (class) 中的屬性 (attribute) ,讓屬性只能在類別中建立及修改。

先來看看屬性沒有封裝的情況, Demo 類別有類別屬性 (class attribute) x 及實體屬性 (instance attribute) ix 主要用途是記錄 Demo 建立實體物件的次數,這裡可以看到屬性沒有封裝的話,類別外的程式 (program) 就可以任意修改屬性值,因此如果屬性沒有封裝,就很有可能被外部程式修改,導致程式運作異常

class Demo:
    x = 0
    
    def __init__(self, i):
        self.i = i
        Demo.x += 1
        
d = Demo(1)
print(Demo.x)
Demo.x = 9
print(Demo.x)
d.i = -1
print(d.i)

#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:encapsulate01.py
# 功能:示範定義類別
# 作者:張凱慶

於命令列執行以上程式,結果如下

$ python3 encapsulate01.py
1
9
-1
$

這裡 Demo2 類別示範了封裝的寫法,就是在屬性識別字前加上連續兩個底線,這樣外部程式就無法取得屬性值,也就無法修改屬性

class Demo2:
    __x = 0
    
    def __init__(self, i):
        self.__i = i
        Demo2.__x += 1
        
d = Demo2(1)
print(Demo2.__x)
print(d.i)

#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:encapsulate02.py
# 功能:示範定義類別
# 作者:張凱慶

於命令列執行以上程式,結果如下

$ python3 encapsulate02.py
Traceback (most recent call last):
  File "encapsulate02.py", line 9, in <module>
    print(Demo2.__x)
AttributeError: type object 'Demo2' has no attribute '__x'
$

可是如果還是有需要取得屬性值的話要怎麼辦?簡單的方式就是設定 get 方法 (method) ,如此例的 get_x()get_i() 來取得屬性值

class Demo3:
    __x = 0
    
    def __init__(self, i):
        self.__i = i
        Demo3.__x += 1
    
    @classmethod
    def get_x(cls):
        return cls.__x
    
    def get_i(self):
        return self.__i
        
d = Demo3(1)
print(Demo3.get_x())
print(d.get_i())

#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:encapsulate03.py
# 功能:示範定義類別
# 作者:張凱慶

於命令列執行以上程式,結果如下

$ python3 encapsulate03.py
1
1
$

最後來看看封裝在繼承 (inheritance) 後的情況,此例 Demo4 類別繼承 Demo3 類別, Demo3 類別的類別屬性 __x 及實體屬性 __i 都經過封裝,而 Demo4 的實體物件變數 d 依然可以取得 Demo3 類別的類別屬性 __x 及實體屬性 __i ,因此封裝後的屬性仍會透過繼承機制讓子類別 (subclass) 繼承

from encapsulate03 import Demo3

class Demo4(Demo3):
    pass

d = Demo4(2)
print(Demo4.get_x())
print(d.get_i())

#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:encapsulate04.py
# 功能:示範定義類別
# 作者:張凱慶

於命令列執行以上程式,結果如下

$ python3 encapsulate04.py
1
1
2
2
$

上一頁: 6.5 static 方法與類別方法
Python 速查手冊 - 目錄
下一頁: 6.7 繼承
回 Python 教材首頁