探討 Python 的繼承關係 - tsungjung411/python-study GitHub Wiki

底下探討 field, _field, __field 成員屬性的繼承關係:

class A:
    def __init__(self):
        A.name = 'A.name'
        A.name1 = 'A.name1'
        A._name2 = 'A._name2'
        A.__name3 = 'A.__name3'
        self.name4 = 'a.name4'
        self._name5 = 'a._name5'
        self.__name6 = 'a.__name6'
    # end-of-def
# end-of-class

class B(A):
    def __init__(self):
        B.name = 'B.name'
        B.name1 = 'B.name1'
        B._name2 = 'B._name2'
        B.__name3 = 'B.__name3'
        self.name4 = 'b.name4'
        self._name5 = 'b._name5'
        self.__name6 = 'b._name6'
    # end-of-def
    
    def dump_b_info(self):
        print("super(B, self).name:", super(B,self).name)
        print("super(B, self).name1:", super(B,self).name1)
        print("super(B, self)._name2:", super(B,self)._name2)  
        print("super(B, self).__name3: X (類別私有成員)") # error, 類別私有成員
        print("super(B, self).name4: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error
        print("super(B, self)._name5: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error
        print("super(B, self).__name6: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error
        print()
    # end-of-def
# end-of-class
        
class C(B):
    def __init__(self):
        pass
    # end-of-def
# end-of-class

# ------------------------
# 測試 class & object
# ------------------------
a = A()
print("A.name:", a.name)
print("A.name1:", a.name1)    
print("A._name2:", a._name2)  
print("A.__name3: X (類別私有成員)") # error, 類別私有成員
print("A.self.name4:", a.name4)    
print("A.self._name5:", a._name5)  
print("A.self.__name6: X (類別私有成員)") # error, 類別私有成員
print()

b = B()
b.dump_b_info()
print("B.name:", b.name)
print("B.name1:", b.name1)    
print("B._name2:", b._name2)  
print("B.__name3: X (類別私有成員)") # error, 類別私有成員
print("B.self.name4:", b.name4)    
print("B.self._name5:", b._name5)  
print("B.self.__name6: X (類別私有成員)") # error, 類別私有成員
print()

c = C()
print("dir(C): ", dir(C), end='\n\n')
print("dir(c): ", dir(c), end='\n\n')

print("C.name:", c.name)
print("C.name1:", c.name1)
print("C._name2:", c._name2)  
print("C.__name3: X (類別私有成員)") # error, 類別私有成員
print("C.self.name4: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error   
print("C.self._name5: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error
print("C.self.__name6: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)") # error

執行結果:

A.name: A.name
A.name1: A.name1
A._name2: A._name2
A.__name3: X (類別私有成員)
A.self.name4: a.name4
A.self._name5: a._name5
A.self.__name6: X (類別私有成員)

super(B, self).name: A.name
super(B, self).name1: A.name1
super(B, self)._name2: A._name2
super(B, self).__name3: X (類別私有成員)
super(B, self).name4: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)
super(B, self)._name5: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)
super(B, self).__name6: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)

B.name: B.name
B.name1: B.name1
B._name2: B._name2
B.__name3: X (類別私有成員)
B.self.name4: b.name4
B.self._name5: b._name5
B.self.__name6: X (類別私有成員)

dir(C):  ['_A__name3', '_B__name3', '__class__', '__delattr__', 
'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__gt__', '__hash__', '__init__', '__le__', 
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', '__weakref__', '_name2', 'name', 'name1']

dir(c):  ['_A__name3', '_B__name3', '__class__', '__delattr__', 
'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__gt__', '__hash__', '__init__', '__le__', 
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', '__weakref__', '_name2', 'name', 'name1']

C.name: B.name
C.name1: B.name1
C._name2: B._name2
C.__name3: X (類別私有成員)
C.self.name4: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)
C.self._name5: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)
C.self.__name6: X (執行時期宣告,不能被繼承下來,因為它宣告在 self)

說明:

  • 宣告在 class 上,是屬於編譯時期(compile-time)宣告
  • 宣告在 self 上,是屬於執行時期(run-time)宣告
  • [補充] 有些語言宣告(declaration)是指「定義變數型別」,定義(definiation)是指「定義變數型別 + 初始化參數」,這邊的宣告單純指「定義物件成員」
  • 可以看出,__field 不管是宣告在 class 上, 還是 self 上,都無法存取。它是私有的,只有「宣告者」在自己的 class 內部可以存取。
  • 宣告在 self 上,不管是 field 還是 _field,都無法被繼承下來的(因為屬性是 runtime 掛上去的,當然不會出現在子類別),只有需告在 class 才能夠被繼承下來。
⚠️ **GitHub.com Fallback** ⚠️