Python 的 underscore 和 hidden object

嚴格來說,python 並沒有 private 的概念
如果要把一個東西做 hidden,建議用一個 underscore 好
兩個 underscore 會 trigger 一個叫 name mangling (mangle: 軋壓) 的動作

詳細的底線介紹請看:
到底是在__底線__什麼啦

在課堂上以哲給的範例裡:

=============
class FirstClass:
    
    string = "Apple"
    __string = "Banana"
    
    def fun(self, language = None):
        if language is not None:
            print (language + " : Hello World!")
        else:
            print("Hello World!")
    
    def __notfun(self):
        print("Learn Python")
        
    def showhidden(self):
        self.__notfun()
        
class SecondClass(FirstClass):
    
    def duringclass(self):
        print("eating " + self.string)
        
    def afterclass(self):
        print("eating " + self.__string)
        
    def __notfun(self):
        super().__notfun()
        print("Write code")
==============================
如果執行:
my_class = SecondClass()
my_class.afterclass()
會出現error
AttributeError: 'SecondClass' object has no attribute '_SecondClass__string'

原因是,如果用2個底線,在解讀時 python 會強迫解讀成 _當前的class__string
但是當前的class沒有__string這個變數
所以出現error

如果要在 firstclass 產生一個 hidden attribute,令 secondClass 也可以使用
請用一個underscore就好。

==============================
為了更深入解釋上面 name mangling 的概念,我改了一下程式

====
class FirstClass:
    
    string = "Apple"
    _string = "Orange"
    _string2= "Grava"
    __string = "Banana"
    __string2 = "Durian"

            
    def doubleline(self):
        print('The __string is ', self.__string)
        print('The __string2 is ', self.__string2)
        
    def showhidden(self):
        print('the hidden _string is ', self._string)
        print('the hidden _string2 is ', self._string2)
        
class SecondClass(FirstClass):
    _string = "Grape"
    __string = "mango"
        
    def doubleline2(self):
        print("The __string is " + self.__string)
        print("The __string2 is " + self.__string2)

=============
在 FirstClasss 裡面
my_obj.doubleline()
The __string is  Banana
The __string2 is  Durian

my_obj.showhidden()
the hidden _string is  Orange
the hidden _string2 is  Grava

===

另外, 在 SecondClass 裡面:

my_class = SecondClass()

my_class.showhidden()
the hidden _string is  Grape
the hidden _string2 is  Grava

my_class.doubleline()
The __string is  Banana
The __string2 is  Durian

my_class.doubleline2()
The __string is mango
Traceback (most recent call last):

  File "<ipython-input-50-eb64d22ea2c3>", line 1, in <module>
    my_class.doubleline2()

  File "<ipython-input-43-044dc11a7d6f>", line 25, in doubleline2
    print("The __string2 is " + self.__string2)

AttributeError: 'SecondClass' object has no attribute '_SecondClass__string2'

看出差別了嗎?
showhidden和doubleline同樣都是定義在父類別裡面
但是在 子類別裡面的showhidden
1. 先去抓子類別新定義出來的 _string, 結果是 Grape,
2. 再去找_string2,因為子類別沒有定義新的 _string2,所以去父類別抓,結果是 Durian。
然而子類別的 doubleline 抓的完全是父類別的變數,就算子類別也有自己的 __string,他不管。
因為 doubleline 在父類別裡方法生成時,就指定是抓父類別的 __string。
最後新的 doubleline2,方法裡指定的是 self.__string 和 self.__string2,
所以只會在自己(子)的類別裡抓這兩個變數,
結果 __string = mango
但是 __string2 在子類別沒有定義,所以出現 error。

【參考資料】
前後單雙底線的解釋:
https://aji.tw/python%E4%BD%A0%E5%88%B0%E5%BA%95%E6%98%AF%E5%9C%A8__%E5%BA%95%E7%B7%9A__%E4%BB%80%E9%BA%BC%E5%95%A6/

雙底線在 python class 裡的意涵:


https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name

這個人遇到了和我們類似的問題,回覆的人給了一樣的答覆:
https://stackoverflow.com/questions/17947250/python-hide-member-of-base-class-in-derived-class


留言

熱門文章