今天沒有新進度,只是寫code印證一下之前的「理論」。
先定義父類別:
class Tree():
    _count = 0    # protected     
    def __init__(self, breed: str, age: int, height: int):   # constructor
        self.breed = breed          # public
        self._age = age             # protected
        self.__height = height      # private
        Tree._count += 1
    def show_info(self):
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
    @classmethod
    def show_count(cls):
        print(f'{cls._count=}')
上面這段code,有公開層級的breed,保護層級的_age和私有層級的__height三個實例屬性,還有一個「保護」(註1)層級的類別屬性__count。
子類別設一個就好。其中show_hardwood_count(cls)的方法,加不加@classmethod裝飾器,似乎不會影響結果:
class Hardwood(Tree):   # derived from Tree()
    # 無自己的constructor。
    # @classmethod   # 不管加不加這個decorator都沒問題。
    def show_hardwood_count(cls):
        print(f'{cls._count = :<10}')
試從子類別取父類別的類別屬性_count:
try:
    hardwood = Hardwood('cedar', 1_000, 57)
    hardwood.show_hardwood_count()
except Exception as e:
    print(str(e)) 
結果順利取到資料:
這是當然的,因為類別屬性_count只是保護層級。就算在C-like這掛真正有保護層級的物件導向語言,保護級的屬性,子類別都是存取得到的。況且Python的保護層級,只是「約定俗成」,語法上的效果就和公開層級無異。
父類別重新設計,將_count改為私有層級的__count:
class Tree():
    __count = 0     # private    
    def __init__(self, breed: str, age: int, height: int):   # constructor
        self.breed = breed       # public
        self._age = age          # protected
        self.__height = height   # private
        Tree.__count += 1
    def show_info(self):
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
    @classmethod
    def show_count(cls):
        print(f'{cls.__count=}')
子類別設計隨著略加修改:
class Hardwood(Tree):   # 繼承自Tree。
    @classmethod
    def show_hardwood_count(cls):
        print(f'{cls.__count = :<10}')  # 只改這行。
測試程式倒不必改,不過還是再貼一次比較清楚:
try:
    hardwood = Hardwood('cedar', 1_000, 57)
    hardwood.show_hardwood_count()
except Exception as e:
    print(str(e)) 
結果拋出異常:
以上證明子類別無法存取父類別中私有層級的類別屬性。
再看實例屬性。父類別的設計和上面完全相同。為方便讀者閱讀,還是再貼一次:
class Tree():
    __count = 0     # private    
    def __init__(self, breed: str, age: int, height: int):   # constructor
        self.breed = breed       # public
        self._age = age          # protected
        self.__height = height   # private
        Tree.__count += 1
    def show_info(self):
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
    @classmethod
    def show_count(cls):
        print(f'{cls.__count=}')
子類別則改為這樣:
class Hardwood(Tree):   # 繼承自Tree。
    def show_hardwood_info(self):
        print(f'{self.breed=:10}{self._age=:<10,}')
        print(f'{self.__height=}')
測試程式:建立一個Hardwood型別的物件,看能否在子類別內部存取父類別的私有層級實例屬性:
try:
    hardwood = Hardwood('cedar', 1_000, 57)
    hardwood.show_hardwood_info()
except Exception as e:
    print(str(e)) 
結果依然拋出異常:
小結:本日的「小哉問」子類別存取父類別的Private Attributes,真的不行嗎?,答案是:Yes, 真的不行。
接下來要驗證子類別是否能呼叫父類別的私有方法:
class Tree():
    def __init__(self, breed: str, age: int, height: int):   # constructor
        self.breed = breed
        self._age = age
        self.__height = height
    def show_info(self):     # public method
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
    def _show_info(self):    # protected method
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
    def __show_info(self):   # private method
        print(f'{self.breed=:10}{self._age=:<10,}{self.__height=:<10,}')
class Hardwood(Tree):   # Inherited from Tree
    ...
測試程式:
try:
    hardwood = Hardwood('cedar', 3_560, 61)
    hardwood.show_info()     # fine
    hardwood._show_info()    # fine
    hardwood.__show_info()   # 這行會觸發exception。
except Exception as e:
    print(str(e))   
結果是:前兩行呼叫父類別hardwood.show_info()(公開)、hardwood._show_info()(保護)的方法都順利執行,而在呼叫父類別的私有方法hardwood.__show_info()時,踢到了一塊大鐵板。
證明私有方法也不會傳給子孫。
註1: 別忘了筆者一再強調的:Python類別中保護層級的屬性和方法,只是大家約定的「默契」,並無實質「公權力」。