Super 你真的理解了嗎?
阿新 • • 發佈:2018-12-16
1.如果重寫了父類的方法,還有沒有必要使用父類的方法。
看下邊的例子簡單介紹呼叫父類的方法。
class A:
def said(self):
print("A")
class B(A):
def said(self):
print("B")
super().said()
b=B()
b.said()
#列印結果
B
A
上邊的例子,既然重寫了父類的方法, 為什麼還要呼叫super, 下邊我們解決這個問題。上邊是沒有必要呼叫父類,但是下邊的程式碼是有必要的,你做下比較。
from threading import Thread class Mytread(Thread): def __init__(self,name,user): self.user=user super().__init__(name=name) #呼叫了父類的name 的屬性
這樣的好處呢,複用父類的name 屬性,就不必新增對name屬性新增額外的程式碼,因為父類已經實現了。 看下 父類屬性的程式碼如下:
def __init__(self, group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None): assert group is None, "group argument must be None for now" if kwargs is None: kwargs = {} self._target = target self._name = str(name or _newname()) self._args = args self._kwargs = kwargs if daemon is not None: self._daemonic = daemon else: self._daemonic = current_thread().daemon self._ident = None self._tstate_lock = None self._started = Event() self._is_stopped = False self._initialized = True # sys.stderr is not stored in the class like # sys.exc_info since it can be changed between instances self._stderr = _sys.stderr # For debugging and _after_fork() _dangling.add(self)
總結如果不是完全覆蓋父類函式,這個就可以複用父類的部分屬性。 如果父類完全可以替代子類的建構函式,就沒有必要重寫父類方法,全部用父類的方法。 跟父類的方法沒有聯絡,是子類獨特的特性,這個需要自己新增子類自己建構函式 或者屬性。
2.當存在多繼承的時候,讀取父類的順序是什麼樣呢?
前面我們也講了當有多重繼承的時候,讀取方法和屬性用的MRO 讀取順序,但是有了super的時候就變得更復雜了,這個是重點一定要注意,否則讀取的父類就亂套,先看下這個例子。
class A: def __init__(self): print("A") class B(A): #繼承父類A def __init__(self): print("B") super().__init__() #呼叫父類的 init class C(A): #繼承父類A def __init__(self): print("C") super().__init__() #呼叫父類的 init class D(B,C): #繼承父類B,C def __init__(self): print("D") super().__init__() #呼叫父類的 init d=D() #列印結果是 D B C A
大家一定有疑問,為什麼 從B 不直接讀取B 的父類A 呢, 直接 去讀C 了呢 ? 答案是: 多重繼承關係都有優先順序的,也是我們經常介紹的 MRO 讀取路徑,python有自省機制可以用MRO函式查到他的路徑,我們一起看看吧。
print(D.__mro__)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
由於D 同時繼承了B和C ,由於B 在前面 優先順序高於C , 所以MRO 路線是 D>B>C>A 正好跟我們列印的順序一樣。 這也解決我們的題目的疑問。