本文目錄一覽:
Python類的繼承和多態代碼詳解
Python類的繼承和多態代碼詳解
Python類的繼承
在OOP(ObjectOrientedProgramming)程序設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Baseclass、Superclass)。
我們先來定義一個classPerson,表示人,定義屬性變數name及sex(姓名和性別);
定義一個方法print_title():當sex是male時,printman;當sex是female時,printwoman。參考如下代碼:
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex
def print_title(self):
if self.sex == “male”:
print(“man”)
elif self.sex == “female”:
print(“woman”)
class Child(Person): # Child 繼承 Person
pass
May = Child(“May”,”female”)
Peter = Person(“Peter”,”male”)
print(May.name,May.sex,Peter.name,Peter.sex) # 子類繼承父類方法及屬性
May.print_title()
Peter.print_title()
而我們編寫Child類,完全可以繼承Person類(Child就是Person);使用classsubclass_name(baseclass_name)來表示繼承;
繼承有什麼好處?最大的好處是子類獲得了父類的全部屬性及功能。如下Child類就可以直接使用父類的print_title()方法
實例化Child的時候,子類繼承了父類的構造函數,就需要提供父類Person要求的兩個屬性變數name及sex:
在繼承關係中,如果一個實例的數據類型是某個子類,那它也可以被看做是父類(May既是Child又是Person)。但是,反過來就不行(Peter僅是Person,而不是Child)。
繼承還可以一級一級地繼承下來,就好比從爺爺到爸爸、再到兒子這樣的關係。而任何類,最終都可以追溯到根類object,這些繼承關係看上去就像一顆倒著的樹。比如如下的繼承樹:
isinstance()及issubclass()
Python與其他語言不同點在於,當我們定義一個class的時候,我們實際上就定義了一種數據類型。我們定義的數據類型和Python自帶的數據類型,比如str、list、dict沒什麼兩樣。
Python有兩個判斷繼承的函數:isinstance()用於檢查實例類型;issubclass()用於檢查類繼承。參見下方示例:
class Person(object):
pass
class Child(Person): # Child 繼承 Person
pass
May = Child()
Peter = Person()
print(isinstance(May,Child)) # True
print(isinstance(May,Person)) # True
print(isinstance(Peter,Child)) # False
print(isinstance(Peter,Person)) # True
print(issubclass(Child,Person)) # True
Python類的多態
在說明多態是什麼之前,我們在Child類中重寫print_title()方法:若為male,printboy;若為female,printgirl
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex
def print_title(self):
if self.sex == “male”:
print(“man”)
elif self.sex == “female”:
print(“woman”)
class Child(Person): # Child 繼承 Person
def print_title(self):
if self.sex == “male”:
print(“boy”)
elif self.sex == “female”:
print(“girl”)
May = Child(“May”,”female”)
Peter = Person(“Peter”,”male”)
print(May.name,May.sex,Peter.name,Peter.sex)
May.print_title()
Peter.print_title()
當子類和父類都存在相同的print_title()方法時,子類的print_title()覆蓋了父類的print_title(),在代碼運行時,會調用子類的print_title()
這樣,我們就獲得了繼承的另一個好處:多態。
多態的好處就是,當我們需要傳入更多的子類,例如新增Teenagers、Grownups等時,我們只需要繼承Person類型就可以了,而print_title()方法既可以直不重寫(即使用Person的),也可以重寫一個特有的。這就是多態的意思。調用方只管調用,不管細節,而當我們新增一種Person的子類時,只要確保新方法編寫正確,而不用管原來的代碼。這就是著名的「開閉」原則:
對擴展開放(Openforextension):允許子類重寫方法函數
對修改封閉(Closedformodification):不重寫,直接繼承父類方法函數
子類重寫構造函數
子類可以沒有構造函數,表示同父類構造一致;子類也可重寫構造函數;現在,我們需要在子類Child中新增兩個屬性變數:mother和father,我們可以構造如下(建議子類調用父類的構造方法,參見後續代碼):
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex
class Child(Person): # Child 繼承 Person
def __init__(self,name,sex,mother,father):
self.name = name
self.sex = sex
self.mother = mother
self.father = father
May = Child(“May”,”female”,”April”,”June”)
print(May.name,May.sex,May.mother,May.father)
Person
若父類構造函數包含很多屬性,子類僅需新增1、2個,會有不少冗餘的代碼,這邊,子類可對父類的構造方法進行調用,參考如下:
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex
class Child(Person): # Child 繼承 Person
def __init__(self,name,sex,mother,father):
Person.__init__(self,name,sex) # 子類對父類的構造方法的調用
self.mother = mother
self.father = father
May = Child(“May”,”female”,”April”,”June”)
print(May.name,May.sex,May.mother,May.father)
多重繼承
多重繼承的概念應該比較好理解,比如現在需要新建一個類baby繼承Child,可繼承父類及父類上層類的屬性及方法,優先使用層類近的方法,代碼參考如下:
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex
def print_title(self):
if self.sex == “male”:
print(“man”)
elif self.sex == “female”:
print(“woman”)
class Child(Person):
pass
class Baby(Child):
pass
May = Baby(“May”,”female”) # 繼承上上層父類的屬性
print(May.name,May.sex)
May.print_title() # 可使用上上層父類的方法
class Child(Person):
def print_title(self):
if self.sex == “male”:
print(“boy”)
elif self.sex == “female”:
print(“girl”)
class Baby(Child):
pass
May = Baby(“May”,”female”)
May.print_title() # 優先使用上層類的方法
總結
以上就是本文關於Python類的繼承和多態代碼詳解的全部內容,希望對大家有所幫助。
Python 實現slots的繼承
__slots__ 是python的一大神器。
它有兩大的特點:
python文檔中這樣介紹它
首先第一點,python的動態性一部分源自於 __dict__ ,屬性都保存在 __dict__ 的一個字典中,我們可以隨時向這個字典添加新內容,這是 MonkeyPatch 的能力。
而當我們顯示的聲明了 __slots__ ,python將不會給這個類創建 __dict__ 和 __weakref__
沒有了 __dict__ 我們便不能隨意創建實例屬性,而必須遵守 __slots__ 的約定。
對於性能而言,使用了 __slots__ 後,屬性會直接存儲到對象中,而不是 __dict__ 中,相當於少了一次檢索步驟。
__slots__ 的兩大優點,對於python來說,是難以拒絕的誘惑。既能限制不必要的動態性,又能提高性能!
但是 __slots__ 遇到繼承時,就會出現很多問題。準確的說, __slots__ 不會被繼承。當我們用一個不帶有 __slots__ 的子類,繼承帶有 __slots__ 的父類時。子類還是會生成 __dict__ 和 __weakref__ 。
這是之前寫的一個metaclass,創建新的類對象時,會進行以下邏輯。
實際上我們的目的正是解決,父類規定的 __slots__ 約束不了無 __slots__ 子類的問題。這個結果令人非常滿意
注意這裡子類的d,在 pycharm 等IDE中不會提示錯誤,因為 pycharm 無法探知你的metaclass做了這樣 逆天改命 的邏輯。
需要注意一點, __slots__ 是 類對實例屬性的約束 ,而類對象無法通過該屬性,約束自己。即為類對象添加新屬性,仍然是被允許的。
按照正常思路,也許我們應該到metaclass寫一個 __slots__ ,但實際上這是不被允許的。
抽空找時間我會考慮下有無可行性。
說說 Python 的繼承
如果要編寫的類是另一個類的特殊版本時,那麼就可以使用繼承 。原有的類稱為父類 , 新類稱為子類 。 子類繼承了父類的所有屬性和方法, 同時子類還可以自定義自己的屬性和方法。
定義子類的實例時, 可以通過 子類的 __init__() 方法,給父類的所有屬性賦值。
假設有這樣的一個 User 類:
接著,我們定義一個 Admin 類,讓它繼承 User 類:
運行結果:
super() 是一個特殊函數, 它會把父類和子類關聯起來。因為父類也稱為超類 ( superclass),所以這個函數叫做 super。接著調用父類的 __init__() 方法, 讓子類包含父類的所有屬性。
子類除了擁有繼承父類而來的屬性和方法之外,還可以自定義子類自己的屬性和方法。
一般情況下,管理員賬號比普通賬號,擁有更高級別的許可權。因此,我們為 Admin 定義一個有別於 User 的 privileges 屬性,並定義一個 「列印擁有的許可權」 的新方法:
運行結果:
對於繼承而來的父類方法, 如果它不符合子類所期望的行為,那麼就可以對其重寫。 只要在子類中定義一個與父類同名的方法,即可實現重寫。
User 本身定義了一個 「是否驗證通過」 的方法,Admin 是管理員,所以需要在列印日誌中特別標註出來,這時就需要重寫父類定義的方法:
運行結果:
通過重寫父類方法, 我們就可以讓子類即可以保留或改寫從父類取其精華,棄其「糟粕」啦。
當實體越來越複雜,對應的類變得越來越大時, 我們可以將這個大型類拆分成多個可協同工作的小類。
比如,賬號許可權,其實即使是普通賬號也是有某些許可權的。所以我們把許可權定義為一個類,然後在 Admin 中使用它:
python有關類繼承的問題
子類繼承父類就是在父類部分的基礎上加上一些子類擴展的屬性、方法以及重寫的父類方法。所以構造一個子類對象時要先構造它的父類部分,構造父類部分就需要調用父類的構造函數。
python拋出異常如何操作?
8.4. 拋出異常
raise 語句允許程序員強制拋出一個指定的異常。例如:
raise NameError(‘HiThere’)
Traceback (most recent call last):
File “
“, line 1, in ?
NameError: HiThere
要拋出的異常由 raise 的唯一參數標識。它必需是一個異常實例或異常類(繼承自 Exception 的類)。
如果你需要明確一個異常是否拋出,但不想處理它,raise 語句可以讓你很簡單的重新拋出該異常:
try:
… raise NameError(‘HiThere’)
… except NameError:
… print(‘An exception flew by!’)
… raise
…
An exception flew by!
Traceback (most recent call last):
File “
“, line 2, in ?
NameError: HiThere
原創文章,作者:LQZP,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/137521.html