Python 進階_OOP 面向對象編程_類和繼承
目錄
目錄
類
最簡單的類
類方法
構造器 __init__
創建一個類
實例化一個對象
調用實例的方法和屬性
創建子類
使用 super 來調用父類的構造器
實例化子類對象
調用子類的屬性和方法
類屬性方法的命名規則
類
類是實例的抽象, 實例是類的具體化.
Python 中的類分為 經典類 和 新式類. 前者現在已經很少用到了, 其特點就是可以不需要繼承任何父類;后者則剛好相反, 形式類必須至少有一個父類, 如果沒有特定的父類需要繼承時, 至少需要繼承基類 object, 在后面給出例子.
最簡單的類
一個最簡單的類可以不具有任何的函數, 僅僅是用作生成一個命名的空間.
In [1]: class MyData(object): ...: pass ...: In [2]: mydata = MyData() In [3]: mydata.x = 1 In [4]: mydata.y = 2 In [5]: mydata.x + mydata.y Out[5]: 3
1
2
3
4
5
6
7
8
9
10
11
12
這樣的類作為容器對象來共享命名空間, 類 MyData 的實例 mydata 將 mydata.x 和 mydata.y 關聯到同一個命名空間中, 所以也只能通過實例名稱結合句點標識符 ‘.’ 來調用, 這就是所謂的使用類作為命名空間容器. 需要注意的是, x 和 y 并不是類的屬性而是實例的屬性.
類方法
類方法定義在類的代碼塊中, 只能被類的實例調用, 所以在定義了一個類方法之后, 如果想調用它需要通過下面幾個步驟:
1. 創建一個實例對象
2. 用實例對象結合句點標識符調用此類方法
class MyData(object): def print_foo(self): print "You invoked print_foo()!" if __name__ == '__main__': mydata = MyData() mydata.print_foo()
1
2
3
4
5
6
7
上面的函數聲明中有一個 self 形參, 這是所有類函數都必須帶有的形參, 表示類的實例對象. 類似與 Java 的 this 關鍵字. 在實例化對象后(生成類實例的過程), 使用類的實例對象調用類函數時, Python 解析器會自動的將類實例對象的引用傳遞給 self 形參, 所以我們不需要顯示的傳遞該形參的實參. 所以當我使用類 MyData 的實例對象 mydata 調用類函數 print_foo() 時, 并沒由傳入任何的實參.
那么為什么需要傳遞類的實例對象給 self 形參呢?
就像之前提到的, 類函數只能通過類實例來調用, 實際上在類定義中我們會頻繁的使用到 self 關鍵字, 這是為了保證類定義內的屬性和函數都是被類的實例化對象所調用的, 而且可以實現創建多個不同的類對象。支撐了封裝(保證數據的隔離是安全)的實現. self 關鍵字還有許多需要注意的地方, 這個我們以后再聊.
構造器 __init__()
類函數 __init__() 是 Python 類中預定義的方法,需要被重載才會生效。以雙下劃線 “__” 開頭和結尾, 在 Python 中使用這種命名方式的方法會被理解為是一種特殊方法, Python 的特殊方法功能非常豐富, 種類也很多, 在聲明變量名的時候要注意不要和特殊方法重名.
通常,構造器用于在 實例化對象被創建后,返回這個實例之前 的這段時間里,執行一些特定的任務或設置。例如:初始化實例對象屬性(以 self 關鍵字調用的屬性)。它在實例化一個新的對象時被自動調用,所以除了初始化實例屬性之外,還常被用于運行一些初步的診斷代碼。其調用的具體步驟:
1. 創建類的實例化對象
2. Python 解析器檢查類是否實現了構造器
3. 若有,則執行構造器的實現,且要求創建對象的時候傳入對應的實參。實例對象會傳遞給第一個形參 self 。
4. 若沒有,則直接返回實例對象
一般建議在構造器中設定需要初始化的實例屬性
創建一個類
class AddBrookEntry(object): """Address book entry class.""" def __init__(self, name, phone): self.name = name self.phone = phone print "Create instance for:", self.name def updatePhone(self, new_phone): self.phone = new_phone print "Update the phone# for:", self.phone
1
2
3
4
5
6
7
8
9
10
11
實例化一個對象
In [3]: jmilkfan = AddrBookEntry('fanguiju', '123-123-123') Create instance for: fanguiju
1
2
NOTE: 在實例化有一個類對象時,需要傳遞類構造函數中的所有形參,否則會出現 TypeError,所以說構造器的作用之一就是初始化類實例對象所需要的實例屬性。
調用實例的方法和屬性
通過實例化所得到的對象,擁有在類定義中所有使用 self 關鍵字來調用的屬性和方法。這些被稱之為實例化對象的屬性和方法。
In [4]: jmilkfan.name Out[4]: 'fanguiju' In [5]: jmilkfan.phone Out[5]: '123-123-123' In [6]: jmilkfan.updatePhone("456-456-455") Update the phone# for: 456-456-455 In [7]: jmilkfan.phone Out[7]: '456-456-455'
1
2
3
4
5
6
7
8
9
10
11
創建子類
子類的創建通過集成父類的方法來實現,子類擁有父類所有公開的屬性和方法。并且在子類中還可以對這些繼承而來的方法和屬性進行重載(在不改變屬性和方法名的前提之下,修改屬性值或方法的內部實現),而不會影響到父類的定義。所以子類除了集成父類的屬性和方法之外,還可以修改繼承所得到的屬性和方法,也可以定義新的屬性和方法。這樣的話就大大增加了代碼的重用。
NOTE:子類應該擁有自己的構造器,若有,則在實例化子類對象時,除了要傳入子類對象所需要初始化的實參之外,還應傳入實例化父類對象所需要的實參,且需要在子類構造器中顯式的調用父類構造器來完成傳遞這些實參;若沒有,則默認使用父類的構造器。
class EmpAddressBookEntry(AddrBookEntry): "Employee address book entry class" def __init__(self, name, phone, id, email): AddrBookEntry.__init__(name, phone) self.id = id self.email = email print "Create instance for:", self.name def updateEmail(self, new_email): self.email = email print "Update the Email# for:", self.email
1
2
3
4
5
6
7
8
9
10
11
12
因為子類重載了父類的構造器,所以必須顯式(className.__init__())的寫出父類構造器才會被調用。
而且需要注意的是:我們還需要顯式的將 self 傳遞給父類構造器,在子類中的 self 表示子類的實例化對象。所以如果希望子類的實例化對象能夠調用父類的屬性和方法的話就需要將表示子類實例化對象的 self 傳遞給父類,來替換父類的實例化對象,從而實現了將子類的實例化對象綁定到父類。這樣才真正的實現了繼承。
NOTE:
1. 在子類的聲明語句中繼承了父類 AddrBookEntry
2. 在子類的構造器中調用了父類的構造器
3. 在子類中定義了新的子類屬性和方法
使用 super() 來調用父類的構造器
一般來說我們很少使用 AddrBookEntry.__init__(name, phone) 這種方式來調用父類的構造器,因為 Python 支持多繼承,所以我們希望可以有方法讓子類自動的找到父類,這個方法就是 super() .
In [33]: class EmpAddressBookEntry(AddrBookEntry): ...: "Employee address book entry class" ...: ...: def __init__(self, name, phone, id, email): ...: super(EmpAddressBookEntry, self).__init__(name, phone) ...: self.id = id ...: self.email = email ...: print "Create instance for:", self.name ...: ...: def updateEmail(self, new_email): ...: self.email = new_email ...: print "Update the Email# for:", self.email
1
2
3
4
5
6
7
8
9
10
11
12
super(EmpAddressBookEntry, self) 語句返回了類 EmpAddressBookEntry 的父類,并且通過句點標識符來調用且傳遞了實參數給父類的構造器。
實例化子類對象
In [16]: jmilk_fan = EmpAddressBookEntry('fanguiju', '123-123-123-123', 1, 'fanguiju@gmail.com') Create instance for: fanguiju Create instance for: fanguiju
1
2
3
實例化子類對象時,需要一同傳遞實例化父類對象的實參(name, phone)。
調用子類的屬性和方法
Out[17]: 'fanguiju' In [18]: jmilk_fan.phone Out[18]: '123-123-123-123' In [19]: jmilk_fan.id Out[19]: 1 In [20]: jmilk_fan.email Out[20]: 'fanguiju@gmail.com' In [22]: jmilk_fan.updatePhone("456-456-456") Update the phone# for: 456-456-456 In [23]: jmilk_fan.phone Out[23]: '456-456-456' In [29]: jmilk_fan.email Out[29]: 'fanguiju@163.com'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
因為子類 EmpAddressBookEntry 繼承了父類 AddrBookEntry 所以子類也就擁有了父類的屬性和方法,可以通過子類對象或直接在子類定義中調用。
類/屬性/方法的命名規則
class: 大寫字母開頭的駝峰規則,EG class MyClass()
def: 小寫字母開頭的下劃線駝峰規則,EG def set_my_function()。方法名應當指出對對象執行的操作,為名稱和動詞的結合。
屬性: 全小寫字母的下劃線駝峰規則,EG my_name =。屬性名一般使用名稱,代表一個對象的稱呼。
Python 面向對象編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。