摘要:新的稱為子類,而被繼承的稱為基類父類或超類。繼承最大的好處是子類獲得了父類的全部功能。在繼承關系中,如果一個實例的數據類型是某個子類,那它的數據類型也可以被看做是父類。
在上一篇中我們介紹了模塊和數據結構,這一篇將介紹面向對象編程。
面向對象編程——Object Oriented Programming,簡稱 OOP,是一種程序設計思想。OOP 把對象作為程序的基本單元,一個對象包含了數據和操作數據的函數。它將數據與功能進行組合,并將其包裝在被稱作“對象”的東西內。
在Python中,所有數據類型都可以視為對象,也可以自定義對象。一個類(Class)能夠創建一種新的類型(Type),其中對象(Object)就是類的實例(Instance)。
可以這樣來類比:你可以擁有類型 int 的變量,也就是說存儲整數的變量是 int 類的實例(對象)。
面向對象的設計思想是抽象出Class,根據Class創建Instance。
給對象發消息實際上就是調用對象對應的關聯函數,我們稱之為對象的方法(Method)。
數據封裝、繼承和多態是面向對象的三大特點。
類和實例面向對象最重要的概念就是類(Class)和實例(Instance)。
類:是抽象的模板,比如 Student 類。
實例:是根據類創建出來的一個個具體的“對象”,每個對象都擁有相同的方法,但各自的數據可能不同。
在 Python 中,定義類是通過class關鍵字。class后面緊接著是類名,類名通常是大寫開頭的單詞。緊接著是object,表示該類是從哪個類繼承下來的。通常,如果沒有合適的繼承類,就使用object 類,這是所有類最終都會繼承的類。
創建實例是通過類名加()實現的:
變量bart指向的就是一個Student的實例,后面的0x1032d3470是內存地址,每個object的地址都不一樣,而Student本身則是一個類。
可以自由地給一個實例變量綁定屬性,比如,給實例bart綁定一個name屬性。
在創建實例的時候,把一些我們認為必須綁定的屬性強制填寫進去。通過定義一個特殊的__init__方法,在創建實例的時候,就把name,score等屬性綁上去:
注意_init__前后分別有兩個下劃線。
__init__方法的第一個參數永遠是self,表示創建的實例本身,因此,在__init__方法內部,就可以把各種屬性綁定到self,因為self就指向創建的實例本身。
有了__init__方法,在創建實例的時候,就不能傳入空的參數了,必須傳入與__init__方法匹配的參數,但self不需要傳,Python 解釋器自己會把實例變量傳進去。
和普通的函數相比,在類中定義的函數只有一點不同,就是第一個參數永遠是實例變量self,并且,調用時不用傳遞該參數。除此之外,類的方法和普通函數沒有什么區別,仍然可以用默認參數、可變參數、關鍵字參數和命名關鍵字參數。
數據封裝在上面的Student類中,每個實例就擁有各自的name和score這些數據。我們可以通過函數來訪問這些數據,比如打印一個學生的成績:
既然Student實例本身就擁有這些數據,要訪問這些數據,就沒有必要從外面的函數去訪問,可以直接在Student類的內部定義訪問數據的函數,這樣,就把“數據”給封裝起來了。、
這些封裝數據的函數是和Student類本身是關聯起來的,我們稱之為類的方法:
要定義一個方法,除了第一個參數是self外,其他和普通函數一樣。要調用一個方法,只需要在實例變量上直接調用,除了self不用傳遞,其他參數正常傳入:
這樣,我們從外部看Student類,就只需要知道創建實例需要給出name和score,而如何打印,都是在Student類的內部定義的,這些數據和邏輯被“封裝”起來了,調用很容易,但卻不用知道內部實現的細節。
類是創建實例的模板,而實例則是一個一個具體的對象,各個實例擁有的數據都互相獨立,互不影響;
方法就是與實例綁定的函數,和普通函數不同,方法可以直接訪問實例的數據;
通過在實例上調用方法,我們就直接操作了對象內部的數據,但無需知道方法內部的實現細節。
和靜態語言不同,Python 允許對實例變量綁定任何數據,也就是說,對于兩個實例變量,雖然它們都是同一個類的不同實例,但擁有的變量名稱都可能不同。
繼承和多態在 OOP 程序設計中,當我們定義一個class的時候,可以從某個現有的class繼承。新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。
繼承最大的好處是:子類獲得了父類的全部功能。
也可以對子類增加一些方法。
當子類和父類都存在相同的run()方法時,我們說,子類的run()覆蓋了父類的run(),在代碼運行的時候,總是會調用子類的run()。
這樣,我們就獲得了繼承的另一個好處:多態。
當我們定義一個class的時候,我們實際上就定義了一種數據類型。我們定義的數據類型和 Python 自帶的數據類型,比如str、list、dict沒什么兩樣。在繼承關系中,如果一個實例的數據類型是某個子類,那它的數據類型也可以被看做是父類。但是,反過來就不行。
新增一個Animal的子類,不必對run_twice()做任何修改。實際上,任何依賴Animal作為參數的函數或者方法都可以不加修改地正常運行,原因就在于多態。
多態的意思:
對于一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調用run()方法,而具體調用的run()方法是作用在Animal、Dog、Cat還是Tortoise對象上,由運行時該對象的確切類型決定。
這就是多態真正的威力,調用方只管調用,不管細節,而當我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調用的。這就是著名的“開閉”原則:
對擴展開放:允許新增 Animal 子類;
對修改封閉:不需要修改依賴 Animal 類型的 run_twice( ) 等函數。
任何類,最終都可以追溯到根類object,這些繼承關系看上去就像一顆倒著的樹。比如如下的繼承樹:
對于靜態語言(例如 Java)來說,如果需要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類,否則,將無法調用run()方法。
對于 Python 這樣的動態語言來說,則不一定需要傳入Animal類型。我們只需要保證傳入的對象有一個run()方法就可以了。
這就是動態語言的“鴨子類型”,它并不要求嚴格的繼承體系,一個對象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。
異常在程序運行過程中,總會遇到各種各樣的錯誤。
程序編寫有問題造成的:比如本來應該輸出整數結果輸出了字符串。這種錯誤我們通常稱之為 bug,bug 是必須修復的。
用戶輸入造成的:比如讓用戶輸入 email 地址,結果得到一個空字符串。這種錯誤可以通過檢查用戶輸入來做相應的處理。
完全無法在程序運行過程中預測的:比如寫入文件的時候,磁盤滿了,寫不進去了;或者從網絡抓取數據,網絡突然斷掉了。這類錯誤也稱為異常,在程序中通常是必須處理的,否則,程序會因為各種問題終止并退出。
Python 內置了一套異常處理機制,來幫助我們進行錯誤處理。
調試:跟蹤程序的執行,查看變量的值是否正確。Python 的 pdb 可以讓我們以單步方式執行代碼。
編寫測試:有了良好的測試,就可以在程序修改后反復運行,確保程序輸出符合我們編寫的測試。
錯誤處理
高級語言通常都內置了一套try...except...finally...的錯誤處理機制
try的機制:
try: print("try...") r = 10 / 0 print("result:", r) except ZeroDivisionError as e: print("except:", e) finally: print("finally...") print("END")
當我們認為某些代碼可能會出錯時,就可以用try來運行這段代碼,如果執行出錯,則后續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即except語句塊,執行完except后,如果有finally語句塊,則執行finally語句塊,至此,執行完畢。
可以有多個except來捕獲不同類型的錯誤。如果沒有錯誤發生,可以在except語句塊后面加一個else,當沒有錯誤發生時,會自動執行else語句。
可以跨越多層調用,比如函數main()調用foo(),foo()調用bar(),結果bar()出錯了,這時,只要main()捕獲到了,就可以處理。也就是說,不需要在每個可能出錯的地方去捕獲錯誤,只要在合適的層次去捕獲錯誤就可以了。
Python 所有的錯誤都是從BaseException類派生的,點擊可查看常見的錯誤類型和繼承關系。
如果錯誤沒有被捕獲,它就會一直往上拋,最后被 Python 解釋器捕獲,打印一個錯誤信息,然后程序退出。
錯誤信息第 1 行:
Traceback (most recent call last):
告訴我們這是錯誤的跟蹤信息。
依次往下看,根據錯誤類型,判斷最后的錯誤源頭。
出錯的時候,一定要分析錯誤的調用棧信息,才能定位錯誤的位置。
Python 內置的logging模塊可以非常容易地記錄錯誤信息。同樣是出錯,但程序打印完錯誤信息后會繼續執行,并正常退出。通過配置,logging還可以把錯誤記錄到日志文件里,方便事后排查。
更多更多關于 Python 的學習可閱讀Python 官方文檔,Python 標準庫文檔,Python的第三方庫。
進一步探索標準庫的一個好方法是閱讀由 Doug Hellmann 撰寫的優秀的 Python Module of the Week 系列。
參考鏈接:
簡明Python教程(電子書可閱讀)
廖雪峰Python教程
如有不足,歡迎指正。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/42187.html
摘要:在定義函數時給定的名稱稱作形參,在調用函數時你所提供給函數的值稱作實參。調用函數要調用一個函數,需要知道函數的名稱和參數。默認參數值可以有效幫助解決這一情況。是默認參數定義默認參數要牢記一點默認參數必須指向不變對象。 關于數據科學在做什么,我們已經在前兩篇文章中進行了總結,即專題概述和描述性統計分析。要進行數據科學的探索,需要一個好工具,就是Python。從本篇開始,將總結學習Pyth...
摘要:有一些表示常見圖形的對象稱為塊,完整的集合位于。中的繪圖函數在中,有行標簽列標簽分組信息。密度圖通過計算可能會產生觀測數據的連續概率分布的估計而產生的。在探索式數據分析工作中,同時觀察一組變量的散布圖是很有意義的。 我們在上一篇介紹了 pandas,本篇介紹 matplotlib。 繪圖和可視化 一個用于創建出版質量圖表的桌面繪圖包。 Matplotlib API入門 Figure ...
摘要:提供了使我們能夠快速便捷地處理結構化數據的大量數據結構和函數。結構化數據,例如多維數據矩陣表格行數據,其中各列可能是不同的類型字符串數值日期等。基礎數組和矢量計算高性能科學計算和數據分析的基礎包。 本篇內容為整理《利用Python進行數據分析》,博主使用代碼為 Python3,部分內容和書本有出入。 利用 Python 進行科學計算的實用指南。本書重點介紹了用于高效解決各種數據分析問...
閱讀 1973·2021-10-25 09:48
閱讀 2806·2021-09-22 14:59
閱讀 1764·2019-08-29 16:52
閱讀 871·2019-08-29 16:07
閱讀 2313·2019-08-29 12:38
閱讀 1772·2019-08-26 13:23
閱讀 887·2019-08-26 11:49
閱讀 3283·2019-08-26 10:56