




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Python數(shù)據(jù)分析與實(shí)踐12023/10/28第4章類(lèi)與對(duì)象本章學(xué)習(xí)目標(biāo):?深刻理解Python中類(lèi)、對(duì)象的概念,掌握它們的構(gòu)造和使用?熟練掌握Python面向?qū)ο蟮臉?gòu)造函數(shù)和析構(gòu)函數(shù),以及運(yùn)算符的重載?理解Python類(lèi)的繼承和組合?熟練掌握Python異常處理機(jī)制和內(nèi)置異常類(lèi)?熟練掌握Python自定義異常的方法32023/10/284.1面向?qū)ο?/p>
面向?qū)ο缶幊痰挠⑽娜Q(chēng)為ObjectOrientedProgramming,簡(jiǎn)稱(chēng)OOP,它是一種程序設(shè)計(jì)思想。OOP把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
面向?qū)ο蟮某绦蛟O(shè)計(jì)把計(jì)算機(jī)程序視為一組對(duì)象的集合,而每個(gè)對(duì)象都可以接收其他對(duì)象發(fā)過(guò)來(lái)的消息,并處理這些消息,計(jì)算機(jī)程序的執(zhí)行就是一系列消息在各個(gè)對(duì)象之間傳遞。42023/10/284.1.1面向?qū)ο缶幊?/p>
面向?qū)ο缶幊痰膬?yōu)點(diǎn)是易維護(hù)、易復(fù)用、易擴(kuò)展,由于面向?qū)ο笥蟹庋b、繼承、多態(tài)的特性,可以設(shè)計(jì)出低耦合的系統(tǒng),使系統(tǒng)更加靈活、更加易于維護(hù)。
在Python中所有數(shù)據(jù)類(lèi)型都可以視為對(duì)象,當(dāng)然用戶也可以自定義對(duì)象。自定義的對(duì)象數(shù)據(jù)類(lèi)型就是面向?qū)ο笾械念?lèi)(Class)的概念。52023/10/284.1.1面向?qū)ο缶幊堂嫦驅(qū)ο笫纠篠tudent這種數(shù)據(jù)類(lèi)型應(yīng)該被視為一個(gè)類(lèi),這個(gè)類(lèi)擁有name和score兩個(gè)屬性(Property)。如果要打印一個(gè)學(xué)生的成績(jī),首先必須創(chuàng)建出這個(gè)學(xué)生類(lèi)對(duì)應(yīng)的對(duì)象,然后給對(duì)象發(fā)一個(gè)print_score消息,讓對(duì)象自己把自己的數(shù)據(jù)打印出來(lái)。具體如下:
classStudent(object):def__init__(self,name,score):=nameself.score=scoredefprint_score(self):print("%s:%s"%(,self.score))62023/10/284.1.1面向?qū)ο缶幊探o對(duì)象發(fā)消息實(shí)際上就是調(diào)用對(duì)象對(duì)應(yīng)的關(guān)聯(lián)函數(shù),一般稱(chēng)之為對(duì)象的方法(Method)。面向?qū)ο蟮某绦驅(qū)懗鰜?lái)就像這樣:>>>bart=Student("BartSimpson",59)l>>>isa=Student("LisaSimpson",87)>>>bart.print_score()>>>lisa.print_score()72023/10/284.1.1面向?qū)ο缶幊?/p>
面向?qū)ο箢?lèi)(Class)和實(shí)例(Instance)的設(shè)計(jì)思想是從自然界中來(lái)的。Class是一種抽象概念,比如這里定義的Student是指學(xué)生這個(gè)概念,而實(shí)例(Instance)是一個(gè)個(gè)具體的Student,比如BartSimpson和LisaSimpson是兩個(gè)具體的Student。
所以,面向?qū)ο蟮脑O(shè)計(jì)思想是抽象出Class,根據(jù)Class創(chuàng)建Instance。面向?qū)ο蟮某橄蟪潭纫群瘮?shù)高,因?yàn)橐粋€(gè)Class既包含數(shù)據(jù)又包含操作數(shù)據(jù)的方法。82023/10/284.1.2類(lèi)的抽象與封裝
對(duì)象包含數(shù)據(jù)以及操作這些數(shù)據(jù)的代碼,一個(gè)對(duì)象包含的所有數(shù)據(jù)和代碼可以通過(guò)類(lèi)構(gòu)成一個(gè)用戶定義的數(shù)據(jù)類(lèi)型。事實(shí)上,對(duì)象就是類(lèi)類(lèi)型(classtype)的變量,一旦定義了一個(gè)類(lèi),就可以創(chuàng)建這個(gè)類(lèi)的多個(gè)對(duì)象,每個(gè)對(duì)象與一組數(shù)據(jù)相關(guān),而這組數(shù)據(jù)的類(lèi)型在類(lèi)中定義。因此,一個(gè)類(lèi)就是具有相同類(lèi)型的對(duì)象的抽象,例如杧果、蘋(píng)果和橘子都是fruit類(lèi)的對(duì)象。類(lèi)是用戶定義的數(shù)據(jù)類(lèi)型,但是在一個(gè)程序設(shè)計(jì)語(yǔ)言中,它和內(nèi)建的數(shù)據(jù)類(lèi)型行為相同。比如創(chuàng)建一個(gè)類(lèi)對(duì)象的語(yǔ)法和創(chuàng)建一個(gè)整數(shù)對(duì)象的語(yǔ)法一模一樣。92023/10/284.1.2類(lèi)的抽象與封裝
把數(shù)據(jù)和函數(shù)裝在一個(gè)單獨(dú)的單元(稱(chēng)為類(lèi))的行為稱(chēng)為封裝。數(shù)據(jù)封裝是類(lèi)最典型的特點(diǎn)。數(shù)據(jù)不能被外界訪問(wèn),只能被封裝在同一個(gè)類(lèi)中的函數(shù)訪問(wèn)。這些函數(shù)提供了對(duì)象數(shù)據(jù)和程序之間的接口。避免數(shù)據(jù)被程序直接訪問(wèn)的概念被稱(chēng)為“數(shù)據(jù)隱藏”。102023/10/284.1.2類(lèi)的抽象與封裝
抽象指僅表現(xiàn)核心的特性而不描述背景細(xì)節(jié)的行為。類(lèi)使用了抽象的概念,并且被定義為一系列抽象的屬性,例如尺寸、重量和價(jià)格,以及操作這些屬性的函數(shù)。類(lèi)封裝了將要被創(chuàng)建的對(duì)象的所有核心屬性。因?yàn)轭?lèi)使用了數(shù)據(jù)抽象的概念,所以它們被稱(chēng)為抽象數(shù)據(jù)類(lèi)型(ADT)。112023/10/284.1.2類(lèi)的抽象與封裝
封裝機(jī)制將數(shù)據(jù)和代碼捆綁到一起,避免了外界的干擾和不確定性。它同樣允許創(chuàng)建對(duì)象。簡(jiǎn)單地說(shuō),一個(gè)對(duì)象就是一個(gè)封裝了數(shù)據(jù)和操作這些數(shù)據(jù)的代碼的邏輯實(shí)體。122023/10/284.1.2類(lèi)的抽象與封裝
在一個(gè)對(duì)象內(nèi)部,某些代碼和(或)某些數(shù)據(jù)可以是私有的,不能被外界訪問(wèn)。通過(guò)這種方式,對(duì)象對(duì)內(nèi)部數(shù)據(jù)提供了不同級(jí)別的保護(hù),以防止程序中無(wú)關(guān)的部分意外地改變或錯(cuò)誤地使用了對(duì)象的私有部分。132023/10/284.1.2類(lèi)的抽象與封裝
簡(jiǎn)而言之,類(lèi)封裝了一系列方法,并且可以通過(guò)一定的規(guī)則約定方法訪問(wèn)權(quán)限。在Python中沒(méi)有public、protected、private之類(lèi)的訪問(wèn)權(quán)限控制修飾詞,Python通過(guò)方法名約定訪問(wèn)權(quán)限。例如:(1)普通名字,表示public。(2)以_前導(dǎo)的名字,從語(yǔ)法上視為public,但約定俗稱(chēng)的意思是“可以被訪問(wèn),但請(qǐng)視為private,不要隨意訪問(wèn)”。(3)以__前導(dǎo)、以__后綴的名字,特殊屬性,表示public。(4)以__前導(dǎo)、不以__后綴的名字,表示private。142023/10/284.1.2類(lèi)的抽象與封裝
private名字不能被繼承類(lèi)引用。private不允許通過(guò)實(shí)例對(duì)象直接訪問(wèn),本質(zhì)上是因?yàn)閜rivate屬性名被Python解釋器改成類(lèi)名屬性名了,因此仍然可以通過(guò)類(lèi)名屬性名訪問(wèn)private屬性,但是不同版本的Python解釋器改造的規(guī)則不一致,通常不建議用戶這樣訪問(wèn)private屬性,因?yàn)榇a不具有可移植性。152023/10/284.1.1類(lèi)的定義與創(chuàng)建
類(lèi)(Class)可以將它或多或少地看作是類(lèi)別或者種類(lèi)的同義詞。在Python中類(lèi)用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。它定義了該集合中每個(gè)對(duì)象所共有的屬性和方法。使用類(lèi)幾乎可以模擬任何東西。162023/10/284.1.1類(lèi)的定義與創(chuàng)建類(lèi)是一個(gè)用戶定義類(lèi)型,與其他大多數(shù)計(jì)算機(jī)語(yǔ)言一樣,Python使用關(guān)鍵字class來(lái)定義類(lèi)。函數(shù)的語(yǔ)法格式如下:classclassname:<statement-1>...<statement-n><statement-1>與<statement-n>內(nèi)可以包含任何有效的Python語(yǔ)句,用來(lái)定義類(lèi)的屬性與方法。4.1.1類(lèi)的定義與創(chuàng)建下面創(chuàng)建一個(gè)簡(jiǎn)單的類(lèi)Cat類(lèi)。classCat():#一次模擬小貓的簡(jiǎn)單嘗試def__init__(self,name,age):#初始化屬性name和ageS=nameSelf.age=agedefsit(self):#模擬小貓被命令下蹲print(.title()+“isnowsitting.”)通過(guò)如上代碼,就可以創(chuàng)建一個(gè)簡(jiǎn)單類(lèi)Cat,賦予了每只小貓下蹲(sit())的能力。4.2.1類(lèi)的定義與創(chuàng)建在上一節(jié)的案例的代碼中,已經(jīng)使用到了一個(gè)類(lèi)中的特殊方法:__init__(self,...)方法,這個(gè)方法被稱(chēng)為構(gòu)造函數(shù),用來(lái)初始化對(duì)象(實(shí)例),在創(chuàng)建新對(duì)象時(shí)調(diào)用。構(gòu)造函數(shù)屬于每個(gè)對(duì)象,每個(gè)對(duì)象都有自己的構(gòu)造函數(shù)。如果用戶未設(shè)計(jì)構(gòu)造函數(shù),Python將提供一個(gè)默認(rèn)的構(gòu)造函數(shù)。__init__方法在類(lèi)的一個(gè)對(duì)象(實(shí)例)被建立時(shí),馬上運(yùn)行。這個(gè)方法可以用來(lái)對(duì)你的對(duì)象做一些你希望的初始化。注意,這個(gè)名稱(chēng)的開(kāi)始和結(jié)尾都是雙下劃線。構(gòu)造函數(shù)的作用有個(gè):一是在內(nèi)存中為類(lèi)創(chuàng)建一個(gè)對(duì)象;二是調(diào)用類(lèi)的初始化方法來(lái)初始化對(duì)象。4.2.1類(lèi)的定義與創(chuàng)建
__init__()方法定義成包含3個(gè)形參,即self、name、age,形參self必不可少,還必須位于其他形參的前面。那么為什么必須在方法定義中包含形參self呢?這是因?yàn)镻ython在調(diào)用這個(gè)__init__()方法創(chuàng)建Cat實(shí)例時(shí)將自動(dòng)傳入實(shí)參self。每個(gè)與類(lèi)相關(guān)聯(lián)的方法調(diào)用都自動(dòng)傳遞實(shí)參self,它是一個(gè)指向?qū)嵗旧淼囊?讓實(shí)例能夠訪問(wèn)類(lèi)中的性和方法。在創(chuàng)建Cat實(shí)例時(shí),Python將調(diào)用Cat類(lèi)的方法__init__()。程序?qū)⑼ㄟ^(guò)實(shí)參向Cat()傳遞名字和年齡;self會(huì)自動(dòng)傳遞,因此不需要手動(dòng)去傳遞它。每當(dāng)根據(jù)Cat類(lèi)創(chuàng)建實(shí)例時(shí)都只需要給最后兩個(gè)形參(name和age)提供值。4.2.1類(lèi)的定義與創(chuàng)建
接下來(lái)創(chuàng)建一個(gè)表示特定小貓的實(shí)例。首先可以將類(lèi)視作有關(guān)如何創(chuàng)建實(shí)例的說(shuō)明,即可以理解成Cat類(lèi)是一系列說(shuō)明,讓Python知道如何創(chuàng)建一個(gè)表示特定小貓的實(shí)例。my_cat=Cat("tommy",3)print("mycat”snameis"+my_.title()+".")print("mycatis"+str(my_cat.age)+"yearsold.")4.2.1類(lèi)的定義與創(chuàng)建
前面創(chuàng)建了一個(gè)簡(jiǎn)單的Cat類(lèi),并在方法__init__()中定義了name和age屬性。如果要訪問(wèn)實(shí)例的屬性,可以使用句點(diǎn)表示法。編寫(xiě)了如下代碼來(lái)訪問(wèn)my_cat的name屬性的值:my_
句點(diǎn)表示法在Python中很有用,這種語(yǔ)法演示了Python語(yǔ)句如何來(lái)獲得屬性的值。4.2.2構(gòu)造函數(shù)
示例代碼中已經(jīng)使用到類(lèi)中的一個(gè)特殊方法———__init__(self,...),這個(gè)方法被稱(chēng)為構(gòu)造函數(shù),用來(lái)初始化對(duì)象(實(shí)例),在創(chuàng)建新對(duì)象時(shí)調(diào)用。__init__()方法在類(lèi)的一個(gè)對(duì)象(實(shí)例)被建立時(shí)馬上運(yùn)行。
這個(gè)方法可以用來(lái)對(duì)用戶的對(duì)象做一些用戶希望的初始化。構(gòu)造函數(shù)屬于每個(gè)對(duì)象,每個(gè)對(duì)象都有自己的構(gòu)造函數(shù)。如果用戶未設(shè)計(jì)構(gòu)造函數(shù),Python將提供一個(gè)默認(rèn)的構(gòu)造函數(shù)。注意,這個(gè)名稱(chēng)的開(kāi)始和結(jié)尾都是雙下畫(huà)線。
構(gòu)造函數(shù)的作用有兩個(gè):一是在內(nèi)存中為類(lèi)創(chuàng)建一個(gè)對(duì)象;二是調(diào)用類(lèi)的初始化方法來(lái)初始化對(duì)象。4.2.2構(gòu)造函數(shù)
類(lèi)的創(chuàng)建和實(shí)例化。classPerson:def__init__(self,name):=namedefsayHi(self):print(“Hello,mynameis”,)p=Person(“python”)p.sayHi()運(yùn)行結(jié)果:Hello,mynameispython4.2.2構(gòu)造函數(shù)
__init__()方法定義為取一個(gè)參數(shù)name(以及普通的參數(shù)self)。在這個(gè)__init__()里只是創(chuàng)建一個(gè)新的域,也稱(chēng)為name。注意它們是兩個(gè)不同的變量,盡管它們有相同的名字。點(diǎn)號(hào)使用戶能夠區(qū)分它們。最重要的是,沒(méi)有專(zhuān)門(mén)調(diào)用__init__()方法,只是在創(chuàng)建一個(gè)類(lèi)的新實(shí)例的時(shí)候把參數(shù)包括在圓括號(hào)內(nèi)跟在類(lèi)名后面,從而傳遞給__init__()方法。這是這種方法的重要之處。4.2.1類(lèi)屬性和實(shí)例屬性
類(lèi)中的屬性分為兩種:一是類(lèi)屬性,二是實(shí)例屬性。類(lèi)屬性是在類(lèi)中方法之外定義的;實(shí)例屬性則是在構(gòu)造函數(shù)__init__中定義的,定義時(shí)以self為前綴,只能通過(guò)對(duì)象名訪問(wèn),上一小節(jié)創(chuàng)建的Cat類(lèi)中的和self.age就是實(shí)例屬性。為了更好的講解類(lèi)屬性,將依據(jù)上一小節(jié)中創(chuàng)建的一個(gè)簡(jiǎn)單類(lèi)Cat,對(duì)其進(jìn)行類(lèi)屬性的增加和修改來(lái)說(shuō)明。類(lèi)屬性的修改和增加都是通過(guò)“類(lèi)名.屬性名”的方式直接進(jìn)行的。4.3.1類(lèi)屬性和實(shí)例屬性增加類(lèi)屬性:classCat():#一次模擬小貓的簡(jiǎn)單嘗試#增加類(lèi)屬性Reproduction_way=“taisheng”Song_way=“miaomiao”def_init_(self,name,age):#初始化屬性name和ageS=nameSelf.age=agedef_sit_(self):#模擬小貓被命令下蹲print(.title()+“isnowsitting.”)4.3.1類(lèi)屬性和實(shí)例屬性如上面的代碼所示,增加了兩個(gè)類(lèi)屬性,分別是生育后代的方式“taisheng”,以及叫聲“miaomiao”,這是貓類(lèi)的共同屬性。4.3.2公有屬性和私有屬性
Python并不直接支持私有方式,而是靠程序員自己把握在外部進(jìn)行特性修改的時(shí)機(jī)。畢竟在使用對(duì)象前應(yīng)該知道如何使用。但是,可以用一些小技巧達(dá)到私有特性的效果。
如果想要讓方法或者特性變?yōu)樗接械?,即從外部無(wú)法進(jìn)行訪問(wèn),只需要在它的名字前面加上雙下劃線即可。具體的講,以__(雙下劃線)開(kāi)頭的屬性是私有屬性,否則這個(gè)屬性就是公有屬性。私有屬性通過(guò)對(duì)象名.類(lèi)名__私有成員名進(jìn)行訪問(wèn),不能在類(lèi)外進(jìn)行直接訪問(wèn)。4.3.2公有屬性和私有屬性定義私有屬性classSecret():def__unaccessible(self):print(“Sorry,youcannotaccessible...”)defaccessible(self):Print(“Yes,youcanaccessible,andthesecretis...”)Self.__unaccessible()現(xiàn)在,如在這個(gè)例子中展示的,__unaccessible是無(wú)法從外界進(jìn)行訪問(wèn)的。4.3.2公有屬性和私有屬性
但是從類(lèi)的內(nèi)部還是能夠進(jìn)行訪問(wèn)的(比如從accessible()進(jìn)行訪問(wèn)):s=Secret()s.__unaccessible()運(yùn)行結(jié)果:Yes,youcanaccessible,andthesecretis...Sorry,youcannotaccessible...4.3.2公有屬性和私有屬性
雙下畫(huà)線雖然有些奇怪,但看起來(lái)像是其他編程語(yǔ)言中的標(biāo)準(zhǔn)的私有方法。事實(shí)上真正發(fā)生的事情是不標(biāo)準(zhǔn)的。因?yàn)樵陬?lèi)的內(nèi)部定義中,所有以雙下畫(huà)線開(kāi)始的命名都將會(huì)被翻譯成前面加單下畫(huà)線和類(lèi)名的形式。例如:Secret._Secret__unaccessible運(yùn)行結(jié)果:unboundmethodSecret.__unaccessible4.3.2公有屬性和私有屬性
總體來(lái)說(shuō),想要確保其他人不會(huì)訪問(wèn)對(duì)象的方法和特性是不可能的,但是像這類(lèi)的“名稱(chēng)變化術(shù)”就是他們不應(yīng)該訪問(wèn)這些方法或者特性的強(qiáng)信號(hào)。
如果不想使用這種方法,但是又想讓其他對(duì)象不能訪問(wèn)內(nèi)部數(shù)據(jù),那么可以使用雙下畫(huà)線。雖然這不過(guò)是一個(gè)習(xí)慣,但的確有實(shí)際效果。例如,前面有下畫(huà)線的名字都不會(huì)被帶星號(hào)的import語(yǔ)句“formmoduleimport*”導(dǎo)入。
有些編程語(yǔ)言支持多種層次的成員變量或特性私有化,比如在Java中就支持4種級(jí)別。盡管單、雙下畫(huà)線在某種程度上給出了兩個(gè)級(jí)別的私有性,但是Python并沒(méi)有真正的私有化支持。4.4.1調(diào)用類(lèi)的方法
在這里,仍舊使用4.2.1小節(jié)中創(chuàng)建的Cat類(lèi)實(shí)例。在創(chuàng)建Cat類(lèi)實(shí)例后,就可以使用句點(diǎn)表示法來(lái)調(diào)用Cat類(lèi)中定義的任何方法。
如果想要調(diào)用類(lèi)中方法,可通過(guò)指定實(shí)例的名稱(chēng)(這里是my_cat)和想要調(diào)用的方法,并用句點(diǎn)分隔它們。遇到代碼my_cat._sit_()時(shí),Python在類(lèi)Cat中查找方法sit()并運(yùn)行其代碼塊。classCat():==snip==my_cat=Cat(“tommy”,3)my_cat._sit_()4.4.2類(lèi)的方法分類(lèi)
在Python中類(lèi)的方法大致上可以分為三類(lèi):類(lèi)方法、實(shí)例方法和靜態(tài)方法。
類(lèi)方法,是類(lèi)對(duì)象所擁有的方法,需要用修飾器“@classmethod”來(lái)標(biāo)識(shí)其為類(lèi)方法。它能夠通過(guò)實(shí)例對(duì)象和類(lèi)對(duì)象去訪問(wèn)。類(lèi)方法的用途就是可以對(duì)類(lèi)屬性進(jìn)行修改。對(duì)于類(lèi)方法,第一個(gè)參數(shù)必須是類(lèi)對(duì)象,一般以“cls”作為第一個(gè)參數(shù)。舉例如下,classpeople:country="china"@classmethoddefgetCountry(cls):#類(lèi)方法returncls.country4.4.2類(lèi)的方法分類(lèi)
實(shí)例方法,在類(lèi)中最常定義的成員方法,它至少有一個(gè)參數(shù)并且必須以實(shí)例對(duì)象作為其第一個(gè)參數(shù),一般以名為’self’的變量作為第一個(gè)參數(shù)。(注意:不能通過(guò)類(lèi)對(duì)象引用實(shí)例方法)。舉例如下,@classmethoddefsetCountry(cls,country):#類(lèi)方法cls.country=countryclassInstanceMethod(object):def__init__(self,a):self.a=adeff1(self):print(“Thisis{0}”.format(self))deff2(self,a):print(“Value:{0}”.format(a))4.4.2類(lèi)的方法分類(lèi)
靜態(tài)方法,需要通過(guò)修飾器”@staticmethod”來(lái)進(jìn)行修飾,靜態(tài)方法對(duì)參數(shù)沒(méi)有要求,不需要多定義參數(shù)。在靜態(tài)方法中只能訪問(wèn)屬于類(lèi)的成員,不能訪問(wèn)屬于對(duì)象的成員,而靜態(tài)方法也只能通過(guò)類(lèi)名調(diào)用。舉例如下,country=“china”@staticmethoddefgetcountry():returnpeople.country@staticmethoddefsetcountry(countryName):people.country=countryName4.4.2類(lèi)的方法分類(lèi)
對(duì)于這三種不同的方法,就出現(xiàn)了一個(gè)問(wèn)題,既然有了實(shí)例方法,類(lèi)方法和靜態(tài)方法與之相比又有什么好處呢?具體的將,在類(lèi)方法中,不管是使用實(shí)例還是類(lèi)調(diào)用方法,都會(huì)把類(lèi)作為第一個(gè)參數(shù)傳遞進(jìn)來(lái),這個(gè)參數(shù)就是類(lèi)本身。如果繼承了這個(gè)使用類(lèi)方法的類(lèi),該類(lèi)的所有子類(lèi)都會(huì)擁有了這個(gè)方法,并且這個(gè)方法會(huì)自動(dòng)指向子類(lèi)本身。靜態(tài)方法是和類(lèi)與實(shí)例都沒(méi)有關(guān)系的,完全可以使用一般方法代替,但是使用靜態(tài)方法可以更好的組織代碼,防止代碼變大后變得比較混亂。類(lèi)方法是可以替代靜態(tài)方法的。靜態(tài)方法不能在繼承中修改。4.4.3析構(gòu)函數(shù)
Python中沒(méi)有專(zhuān)用的構(gòu)造和析構(gòu)函數(shù),但是一般可以在__init__和__del__分別完成初始化和刪除操作,可用這個(gè)替代構(gòu)造和析構(gòu)。從這個(gè)意義上講,__init__方法:屬于python語(yǔ)言的構(gòu)造函數(shù);__del__方法:屬于python語(yǔ)言的析構(gòu)函數(shù),它在對(duì)象消逝的時(shí)候被調(diào)用,用來(lái)釋放對(duì)象占用的資源。析構(gòu)函數(shù)在對(duì)象就要被垃圾回收之前調(diào)用,但發(fā)生調(diào)用的具體時(shí)間是不可知的。4.3.3析構(gòu)函數(shù)將通過(guò)一個(gè)例子來(lái)說(shuō)明Python的析構(gòu)函數(shù),舉例如下,classtest():def__init__(self):print(“AAA”)def__del__(self):print(“BBB”)defmy(self):print(“CCC”)>>>obj=test()AAABBB>>>obj.my()CCC>>>delobjBBB4.3.3析構(gòu)函數(shù)
上述例子中的__del__函數(shù)就是一個(gè)析構(gòu)函數(shù)了,當(dāng)使用del刪除對(duì)象時(shí),會(huì)調(diào)用他本身的析構(gòu)函數(shù),另外當(dāng)對(duì)象在某個(gè)作用域中調(diào)用完畢,在跳出其作用域的同時(shí)析構(gòu)函數(shù)也會(huì)被調(diào)用一次,這樣可以用來(lái)釋放內(nèi)存空間。__del__()也是可選的,如果不提供,則Python會(huì)在后臺(tái)提供默認(rèn)析構(gòu)函數(shù)如果要顯式的調(diào)用析構(gòu)函數(shù),可以使用del關(guān)鍵字,方式如下:
del對(duì)象名412023/10/284.5類(lèi)的繼承
代碼重用是軟件工程的重要目標(biāo)之一,類(lèi)的重用是面向?qū)ο蟮暮诵膬?nèi)容之一在編寫(xiě)類(lèi)時(shí),并非總是要從新開(kāi)始。如果你要編寫(xiě)的類(lèi)是另一個(gè)現(xiàn)成類(lèi)的特殊版本,可使用繼承,在這個(gè)現(xiàn)成類(lèi)的基礎(chǔ)上創(chuàng)建新類(lèi),在所創(chuàng)建的新的類(lèi)中通過(guò)添加代碼,來(lái)擴(kuò)展現(xiàn)成類(lèi)的屬性和方法。這樣不僅能夠減少工作量,而且能降低出現(xiàn)錯(cuò)誤的可能性。422023/10/284.5.1父類(lèi)與子類(lèi)
一個(gè)類(lèi)繼承另一個(gè)類(lèi)時(shí),它將自動(dòng)獲得另一個(gè)類(lèi)的所有屬性和方法,原有的類(lèi)稱(chēng)為基類(lèi)、父類(lèi)或超類(lèi)(Baseclass、Superclass),而新類(lèi)稱(chēng)為子類(lèi)(Subclass)。子類(lèi)繼承了其父類(lèi)的所有屬性和方法,同時(shí)還可以定義自己的屬性和方法。
在繼承關(guān)系中,繼承者是被繼承者的子類(lèi)。子類(lèi)繼承所有祖先的非私有屬性和非私有方法,子類(lèi)也可以增加的屬性和方法,子類(lèi)還可以通過(guò)重定義覆蓋從父類(lèi)中繼承而來(lái)的方法。432023/10/284.5.2繼承的語(yǔ)法具體的繼承語(yǔ)法,通過(guò)一個(gè)實(shí)例來(lái)進(jìn)行展示說(shuō)明,具體如下。例如,我們已經(jīng)編寫(xiě)了一個(gè)名為Animal的class,有一個(gè)run()方法可以直接打印,classAnimal(object):defrun(self):print(“Animalisrunning...”)442023/10/284.5.2繼承的語(yǔ)法當(dāng)我們需要編寫(xiě)Dog和Cat類(lèi)時(shí),就可以直接從Animal類(lèi)繼承:classDog(Animal):passclassCat(Animal):pass
此時(shí),對(duì)于Dog來(lái)說(shuō),Animal就是它的父類(lèi),對(duì)于Animal來(lái)說(shuō),Dog就是它的子類(lèi)。Cat和Dog類(lèi)似。創(chuàng)建子類(lèi)時(shí),父類(lèi)必須包含在當(dāng)前文件中,且位于子類(lèi)前面。我們定義了子類(lèi)Dog和Cat。定義子類(lèi)時(shí),必須在括號(hào)內(nèi)指定父類(lèi)的名稱(chēng)。452023/10/284.5.2繼承的語(yǔ)法
繼承有什么好處?最大的好處是子類(lèi)獲得了父類(lèi)的全部功能。由于Animial實(shí)現(xiàn)了run()方法,因此,Dog和Cat作為它的子類(lèi),什么事也沒(méi)干,就自動(dòng)擁有了run()方法:dog=Dog()dog.run()cat=Cat()cat.run()運(yùn)行結(jié)果如下:Animalisrunning...Animalisrunning...462023/10/284.5.2繼承的語(yǔ)法
繼承的第二個(gè)好處需要用戶對(duì)代碼做一點(diǎn)改進(jìn)。大家可以看到,無(wú)論是Dog還是Cat,它們?cè)趓un()的時(shí)候顯示的都是Animalisrunning...,符合邏輯的做法是分別顯示Dogisrunning...和Catisrunning...,因此對(duì)Dog和Cat類(lèi)改進(jìn)如下:classDog(Animal):defrun(self):print("Dogisrunning...")classCat(Animal):defrun(self):print("Catisrunning...")運(yùn)行結(jié)果如下:Dogisrunning...Catisrunning...472023/10/284.5.2繼承的語(yǔ)法
當(dāng)子類(lèi)和父類(lèi)存在相同的run()方法時(shí),子類(lèi)的run()覆蓋父類(lèi)的run(),在代碼運(yùn)行時(shí)總是會(huì)調(diào)用子類(lèi)的run()。當(dāng)然,用戶也可以給子類(lèi)增加一些方法,比如Dog類(lèi):classDog(Animal):defrun(self):print("Dogisrunning...")defeat(self):print("Eatingmeat...")482023/10/284.5.3多重繼承
繼承是面向?qū)ο缶幊痰囊粋€(gè)重要的方式,因?yàn)橥ㄟ^(guò)繼承,子類(lèi)就可以擴(kuò)展父類(lèi)的功能。以一個(gè)例子來(lái)進(jìn)行講解。492023/10/284.5.3多重繼承
這里想一下Animal類(lèi)層次的設(shè)計(jì),假設(shè)要實(shí)現(xiàn)Dog(狗)、Bat(蝙蝠)、Parrot(鸚鵡)、Ostrich(鴕鳥(niǎo))4種動(dòng)物,如果按照哺乳動(dòng)物和鳥(niǎo)類(lèi)歸類(lèi),可以設(shè)計(jì)出如下類(lèi)層次。?哺乳類(lèi):能跑的哺乳類(lèi),能飛的哺乳類(lèi)。?鳥(niǎo)類(lèi):能跑的鳥(niǎo)類(lèi),能飛的鳥(niǎo)類(lèi)。如果要再增加“寵物類(lèi)”和“非寵物類(lèi)”,那么類(lèi)的數(shù)量會(huì)呈指數(shù)增長(zhǎng),很明顯這樣設(shè)計(jì)是不行的,正確的做法是采用多重繼承。首先,主要的類(lèi)層次仍按照哺乳類(lèi)和鳥(niǎo)類(lèi)設(shè)計(jì)。502023/10/284.5.3多重繼承classAnimal(object):pass#大類(lèi)classMammal(Animal):passclassBird(Animal):pass#各種動(dòng)物classDog(Mammal):passclassBat(Mammal):passclassParrot(Bird):passclassOstrich(Bird):pass512023/10/284.5.3多重繼承
現(xiàn)在,要給動(dòng)物再加上Runnable和Flyable的功能,只需要先定義好Runnable和Flyable的類(lèi):classRunnable(object):defrun(self):print(“Running...”)classFlyable(object):deffly(self):print(“Flying...”)522023/10/284.5.3多重繼承對(duì)于需要Runnable功能的動(dòng)物,就多繼承一個(gè)Runnable,例如Dog:classDog(Mammal,Runnable):pass532023/10/284.5.3多重繼承對(duì)于需要Flyable功能的動(dòng)物,就多繼承一個(gè)Flyable,例如Bat:classBat(Mammal,Flyable):pass通過(guò)多重繼承,一個(gè)子類(lèi)就可以同時(shí)獲得多個(gè)父類(lèi)的所有功能。542023/10/284.5.4運(yùn)算符的重載
在Python類(lèi)中可以重寫(xiě)某些運(yùn)算符的方法函數(shù),例如類(lèi)中提供了__add__()這個(gè)鉤子函數(shù),當(dāng)調(diào)用“+”(加法)運(yùn)算時(shí),實(shí)際上是調(diào)用了__add__()鉤子函數(shù),用戶在類(lèi)中可以重寫(xiě)這些鉤子函數(shù)。552023/10/284.5.4運(yùn)算符的重載
在Python中帶有前/后綴、雙下畫(huà)線的方法函數(shù)稱(chēng)為鉤子函數(shù),鉤子函數(shù)具有以下特征:(1)多數(shù)鉤子函數(shù)均可在類(lèi)中被重寫(xiě)。(2)鉤子函數(shù)無(wú)預(yù)設(shè)值。(3)相應(yīng)運(yùn)算符調(diào)用時(shí)會(huì)自動(dòng)映射調(diào)用這些鉤子函數(shù)。562023/10/284.5.4運(yùn)算符的重載下面表例舉一些常見(jiàn)運(yùn)算符重載方法:methodoverloadcall__init__構(gòu)造函數(shù)對(duì)象創(chuàng)建:X=Class(args)__del__析構(gòu)函數(shù)X對(duì)象收回__add__運(yùn)算法+X+Y,X+=Y__or__運(yùn)算符|X|Y,X|=Y_repr__,__str__打印,轉(zhuǎn)換print(X),repr(X),str(X)__call__函數(shù)調(diào)用X(*args,**kwargs)__getattr__點(diǎn)號(hào)運(yùn)算X.undefined__setattr__屬性賦值語(yǔ)句X.any=value572023/10/284.5.4運(yùn)算符的重載__delattr__屬性刪除delX.any__getattribute__屬性獲取X.any__getitem__索引運(yùn)算X[key],X[i:j]__setitem__索引賦值語(yǔ)句X[key],X[i:j]=sequence__delitem__索引和分片刪除delX[key],delX[i:j]__len__長(zhǎng)度len(X)__bool__布爾測(cè)試bool(X)__lt__,__gt__,__le__,__ge__,__eq__,__ne__特定的比較X<Y,X>Y,X<=Y,X>=Y,X==Y,X!=Y582023/10/284.5.4運(yùn)算符的重載__lt__,__gt__,__le__,__ge__,__eq__,__ne__特定的比較X<Y,X>Y,X<=Y,X>=Y,X==Y,X!=Y__radd__右側(cè)加法other+X__iadd__實(shí)地(增強(qiáng)的)加法X+=Y(orelse__add__)__iter__,__next__迭代環(huán)境I=iter(X),next()__contains__成員關(guān)系測(cè)試iteminX(任何可迭代)__index__整數(shù)值hex(X),bin(X),oct(X)__enter__,__exit__環(huán)境管理器withobjasvar:__get__,__set__,__delete__描述符屬性X.attr,X.attr=value,delX.attr__new__創(chuàng)建在__init__之前創(chuàng)建對(duì)象592023/10/284.6類(lèi)的組合
前面講了面向類(lèi)與對(duì)象的繼承,知道了繼承是一種什么“是”什么的關(guān)系。然而類(lèi)與類(lèi)之間還有另一種關(guān)系,這就是組合。這是類(lèi)的另一種重用的方式,如果程序中的類(lèi)需要使用一個(gè)其他對(duì)象,就可以使用類(lèi)的組合方式。在Python中,一個(gè)類(lèi)可以包含其他類(lèi)的對(duì)象作為屬性,這就是類(lèi)的組合。
先來(lái)看兩個(gè)例子:先定義兩個(gè)類(lèi),一個(gè)老師類(lèi),老師類(lèi)有名字,年齡,出生的年,月和日,所教的課程等特征以及走路,教書(shū)的技能:602023/10/284.6類(lèi)的組合classTeacher:def__init__(self,name,age,year,mon,day):=nameself.age=ageself.year=yearself.mon=monself.day=daydefwalk(self):print(“%siswalkingslowly”%)defteach(self):print(“%sisteaching”%)612023/10/284.6類(lèi)的組合
再定義一個(gè)學(xué)生類(lèi),學(xué)生類(lèi)有名字,年齡,出生的年,月和日,學(xué)習(xí)的組名等特征以及走路,學(xué)習(xí)的技能:622023/10/284.6類(lèi)的組合classStudent:def__init__(self,name,age,year,mon,day):=nameself.age=ageself.year=yearself.mon=monself.day=daydefwalk(self):print(“%siswalkingslowly”%)defstudy(self):print(“%sisstudying”%)632023/10/284.6類(lèi)的組合
根據(jù)類(lèi)的繼承這個(gè)特性,可以把代碼縮減一下。定義一個(gè)人類(lèi),然后再讓老師類(lèi)和學(xué)生類(lèi)繼承人類(lèi)的特征和技能:classPeople:def__init__(self,name,age,year,mon,day):=nameself.age=ageself.year=yearself.mon=monself.day=daydefwalk(self):print(“%siswalking”%)642023/10/284.6類(lèi)的組合classTeacher(People):def__init__(self,name,age,year,mon,day,course):People.__init__(self,name,age,year,mon,day)self.course=coursedefteach(self):print(“%sisteaching”%)classStudent(People):def__init__(self,name,age,year,mon,day,group):People.__init__(self,name,age,year,mon,day)self.group=groupdefstudy(self):print(“%sisstudying”%)652023/10/284.6類(lèi)的組合再對(duì)老師和學(xué)生進(jìn)行實(shí)例化,得到一個(gè)老師和一個(gè)學(xué)生。t1=Teacher(“alex”,28,1989,9,2,“python”)s1=Student(“jack”,22,1995,2,8,“group2”)662023/10/284.6類(lèi)的組合
現(xiàn)在想知道t1和s1的名字、年齡、出生的年/月/日都很容易,但是想一次性打印出t1或s1的生日就不那么容易了,這時(shí)需要用字符串進(jìn)行拼接,有沒(méi)有什么更好的辦法呢?
有,那就是組合。繼承是一個(gè)子類(lèi)與一個(gè)父類(lèi)的關(guān)系,而組合是一個(gè)類(lèi)與另一個(gè)類(lèi)的關(guān)系??梢哉f(shuō)每個(gè)人都有生日,而不能說(shuō)人是生日,這樣就要使用組合的功能。672023/10/284.6類(lèi)的組合
可以把出生的年/月/日再另外定義一個(gè)日期的類(lèi),然后用老師或者學(xué)生類(lèi)與這個(gè)日期的類(lèi)組合起來(lái),就可以很容易地得出老師t1或者學(xué)生s1的生日,再也不用字符串拼接那么麻煩。請(qǐng)看下面的代碼:682023/10/284.6類(lèi)的組合classDate:def__init__(self,year,mon,day):self.year=yearself.mon=monself.day=daydefbirth_info(self):print(“Thebirthis%s-%s-%s”%(self.year,self.mon,self.day))692023/10/284.6類(lèi)的組合classPeople:def__init__(self,name,age,year,mon,day):=nameself.age=ageself.birth=Date(year,mon,day)defwalk(self):print(“%siswalking”%)702023/10/284.6類(lèi)的組合classTeacher(People):def__init__(self,name,age,year,mon,day,course):People.__init__(self,name,age,year,mon,day)self.course=coursedefteach(self):print(“%sisteaching”%)712023/10/284.6類(lèi)的組合classStudent(People):def__init__(self,name,age,year,mon,day,group):People.__init__(self,name,age,year,mon,day)self.group=groupdefstudy(self):print(“%sisstudying”%)t1=Teacher(“alex",28,1989,9,2,"python”)s1=Student(“jack",22,1995,2,8,"group2”)722023/10/284.6類(lèi)的組合
這樣一來(lái),可以使用跟前面一樣的方法來(lái)調(diào)用老師t1或?qū)W生s1的姓名,年齡等特征以及走路,教書(shū)或者學(xué)習(xí)的技能。print()t1.walk()t1.teach()輸出為:alexalexiswalkingalexisteaching732023/10/284.6類(lèi)的組合
那要怎么能夠知道他們的生日呢:print(t1.birth)輸出為:<__main__.Dateobjectat0x0000000002969550>742023/10/284.6類(lèi)的組合
這個(gè)birth是子類(lèi)Teacher從父類(lèi)People繼承過(guò)來(lái)的,而父類(lèi)People的birth又是與Date這個(gè)類(lèi)組合在一起的,所以,這個(gè)birth是一個(gè)對(duì)象。而在Date類(lèi)下面有一個(gè)birth_info的技能,這樣就可以通過(guò)調(diào)用Date下面的birth_info這個(gè)函數(shù)屬性來(lái)知道老師t1的生日了。t1.birth.birth_info()得到的結(jié)果為:Thebirthis1989-9-2752023/10/284.6類(lèi)的組合
組合就是一個(gè)類(lèi)中使用到另一個(gè)類(lèi),從而把幾個(gè)類(lèi)拼到一起。組合的功能也是為了減少重復(fù)代碼。
在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中,如果僅僅是只使用繼承和組合中的一種技術(shù),是很難滿足實(shí)際需求的,所以在實(shí)際的開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)人員通常會(huì)將兩種技術(shù)結(jié)合起來(lái)使用。762023/10/284.7類(lèi)的異常處理異常處理在任何一門(mén)編程語(yǔ)言里都是非常被關(guān)注的一個(gè)話題,良好的異常處理可以讓程序更加健壯,清晰的錯(cuò)誤信息更能幫助快速修復(fù)問(wèn)題。在Python中,和部分高級(jí)語(yǔ)言一樣,使用了try/except語(yǔ)句塊來(lái)處理異常,如果你有其他編程語(yǔ)言的經(jīng)驗(yàn),實(shí)踐起來(lái)并不難。772023/10/284.7.1異常
異常即是在程序執(zhí)行過(guò)程中發(fā)生的影響程序正常運(yùn)行的一個(gè)事件,該事件會(huì)在程序執(zhí)行過(guò)程中發(fā)生,影響了程序的正常執(zhí)行。一般情況下,在Python無(wú)法正常處理程序時(shí)就會(huì)發(fā)生一個(gè)異常。異常是Python對(duì)象,表示一個(gè)錯(cuò)誤。當(dāng)Python腳本發(fā)生異常時(shí)我們需要捕獲處理它,否則程序會(huì)終止執(zhí)行。異常處理使程序能夠處理完異常后繼續(xù)它的正常執(zhí)行,不至于使程序因異常導(dǎo)致退出或崩潰。782023/10/284.7.1異常舉一個(gè)具體的例子:打開(kāi)一個(gè)不存在的文件。代碼如下:fr=open(“/notthere”,”r”)運(yùn)行結(jié)果:Traceback(mostrecentcalllast):File“tiaoshi005.py”,line1,in<module>fr=open(“/notthere”,”r”)FileNotFoundError:[Errno2]Nosuchfileordirectory:‘/notthere’例子中的代碼視圖打開(kāi)一個(gè)不存在的文件,運(yùn)行之后,拋FileNotFoundError異常。4.7.2Python中的異常類(lèi)
Python程序出現(xiàn)異常時(shí)將拋出一個(gè)異常類(lèi)的現(xiàn)象。Python中所有的異常類(lèi)的根類(lèi)都是BaseException類(lèi),他們都是BaseException的直接或間接子類(lèi)。大部分常規(guī)異常類(lèi)的基類(lèi)是Exception的子類(lèi)。下表列出了Python中內(nèi)置的標(biāo)準(zhǔn)異常。而自定義異常類(lèi)都是繼承自這些標(biāo)準(zhǔn)異常。異常名稱(chēng)描述BaseException所有異常的基類(lèi)SystemExit解釋器請(qǐng)求退出KeyboardInterrupt用戶中斷執(zhí)行(通常是輸入^C)Exception常規(guī)錯(cuò)誤的基類(lèi)StopIteration迭代器沒(méi)有更多的值4.7.2Python中的異常類(lèi)GeneratorExit生成器(generator)發(fā)生異常來(lái)通知退出StandardError所有的內(nèi)建標(biāo)準(zhǔn)異常的基類(lèi)ArithmeticError所有數(shù)值計(jì)算錯(cuò)誤的基類(lèi)FloatingPointError浮點(diǎn)計(jì)算錯(cuò)誤OverflowError數(shù)值運(yùn)算超出最大限制ZeroDivisionError除(或取模)零(所有數(shù)據(jù)類(lèi)型)AssertionError斷言語(yǔ)句失敗AttributeError對(duì)象沒(méi)有這個(gè)屬性4.7.2Python中的異常類(lèi)EOFError沒(méi)有內(nèi)建輸入,到達(dá)EOF標(biāo)記EnvironmentError操作系統(tǒng)錯(cuò)誤的基類(lèi)IOError輸入/輸出操作失敗OSError操作系統(tǒng)錯(cuò)誤WindowsError系統(tǒng)調(diào)用失敗ImportError導(dǎo)入模塊/對(duì)象失敗LookupError無(wú)效數(shù)據(jù)查詢的基類(lèi)IndexError序列中沒(méi)有此索引(index)4.7.2Python中的異常類(lèi)KeyError映射中沒(méi)有這個(gè)鍵MemoryError內(nèi)存溢出錯(cuò)誤(對(duì)于Python解釋器不是致命的)NameError未聲明/初始化對(duì)象(沒(méi)有屬性)UnboundLocalError訪問(wèn)未初始化的本地變量ReferenceError弱引用(Weakreference)試圖訪問(wèn)已經(jīng)垃圾回收了的對(duì)象RuntimeError一般的運(yùn)行時(shí)錯(cuò)誤NotImplementedError尚未實(shí)現(xiàn)的方法SyntaxErrorPython語(yǔ)法錯(cuò)誤4.7.2Python中的異常類(lèi)IndentationError縮進(jìn)錯(cuò)誤TabErrorTab和空格混用SystemError一般的解釋器系統(tǒng)錯(cuò)誤TypeError對(duì)類(lèi)型無(wú)效的操作ValueError傳入無(wú)效的參數(shù)UnicodeErrorUnicode相關(guān)的錯(cuò)誤UnicodeDecodeErrorUnicode解碼時(shí)的錯(cuò)誤UnicodeEncodeErrorUnicode編碼時(shí)錯(cuò)誤4.7.2Python中的異常類(lèi)UnicodeTranslateErrorUnicode轉(zhuǎn)換時(shí)錯(cuò)誤Warning警告的基類(lèi)DeprecationWarning關(guān)于被棄用的特征的警告FutureWarning關(guān)于構(gòu)造將來(lái)語(yǔ)義會(huì)有改變的警告OverflowWarning舊的關(guān)于自動(dòng)提升為長(zhǎng)整型(long)的警告PendingDeprecationWarning關(guān)于特性將會(huì)被廢棄的警告RuntimeWarning可疑的運(yùn)行時(shí)行為(runtimebehavior)的警告SyntaxWarning可疑的語(yǔ)法的警告UserWarning用戶代碼生成的警告4.7.3捕獲與處理異常捕捉異常通常使用try/except語(yǔ)句。
try/except語(yǔ)句用來(lái)檢測(cè)try語(yǔ)句塊中的錯(cuò)誤,從而讓except語(yǔ)句捕獲異常信息并處理。如果不想在異常發(fā)生時(shí)結(jié)束程序,只需在try里捕獲它。4.7.3捕獲與處理異常以下為簡(jiǎn)單的try....except的語(yǔ)法:try:<語(yǔ)句>#運(yùn)行別的代碼except<名字>:<語(yǔ)句>#如果在try部份引發(fā)了'name'異常except<名字>,<數(shù)據(jù)>:<語(yǔ)句>#如果引發(fā)了'name'異常,獲得附加的數(shù)據(jù)4.7.3捕獲與處理異常
當(dāng)開(kāi)始一個(gè)try語(yǔ)句后,Python就在當(dāng)前程序的上下文中作標(biāo)記,這樣當(dāng)異常出現(xiàn)時(shí)就可以回到這里,try子句先執(zhí)行,接下來(lái)會(huì)發(fā)生什么依賴(lài)于執(zhí)行時(shí)是否出現(xiàn)異常。
如果當(dāng)try后的語(yǔ)句執(zhí)行時(shí)發(fā)生異常,Python就跳回到try并執(zhí)行第一個(gè)匹配該異常的except子句,異常處理完畢,控制流就通過(guò)整個(gè)try語(yǔ)句(除非在處理異常時(shí)又引發(fā)新的異常)。
如果在try后的語(yǔ)句里發(fā)生了異常,卻沒(méi)有匹配的except子句,異常將被遞交到上層的try,或者到程序的最上層(這樣將結(jié)束程序,并打印缺省的出錯(cuò)信息)。如果在try子句執(zhí)行時(shí)沒(méi)有發(fā)生異常,Python將執(zhí)行else語(yǔ)句后的語(yǔ)句(如果有else的話),然后控制流通過(guò)整個(gè)try語(yǔ)句。4.7.3捕獲與處理異常當(dāng)然也可以不帶任何異常類(lèi)型使用except,如下示例:try:正常的操作......................except:發(fā)生異常,執(zhí)行這塊代碼......................else:如果沒(méi)有異常執(zhí)行這塊代碼以上方式try-except語(yǔ)句捕獲所有發(fā)生的異常。但這不是一個(gè)很好的方式,我們不能通過(guò)該程序識(shí)別出具體的異常信息,因?yàn)樗东@所有的異常。4.7.4自定義異常類(lèi)
通過(guò)創(chuàng)建一個(gè)新的異常類(lèi),程序可以命名自己的異常。自定義異常應(yīng)該是通過(guò)直接或間接的方式繼承自典型的Exception類(lèi)。4.7.4自定義異常類(lèi)
以下為與RuntimeError相關(guān)的實(shí)例,實(shí)例中創(chuàng)建了一個(gè)類(lèi),基類(lèi)為RuntimeError,用于在異常觸發(fā)時(shí)輸出更多的信息。在try語(yǔ)句塊中,用戶自定義的異常后執(zhí)行except塊語(yǔ)句,變量e是用于創(chuàng)建Networkerror類(lèi)的實(shí)例。classNetworkerror(RuntimeError): def__init__(self,arg): self.args=arg4.7.4自定義異常類(lèi)在定義以上類(lèi)后,可以觸發(fā)該異常,如下所示:try: raiseNetworkerror("Badhostname")except(Networkerror)ase: print(e.args)但是,因?yàn)镹etworkerror是一個(gè)自定義類(lèi),因此需要使用raise來(lái)顯式地拋出異常。4.7.4自定義異常類(lèi)
自定義異常的其他使用方法則與標(biāo)準(zhǔn)模塊中的異常類(lèi)的使用方法一致。下面將通過(guò)一個(gè)具體的例子來(lái)進(jìn)行自定義異常使用的詳細(xì)講解。具體如下:classShortInputException(Exception):#Auser-definedexceptionclass.def__init__(self,length,atleast):Exception.__init__(self)self.length=length self.atleast=atleast4.7.4自定義異常類(lèi)try:s=raw_input('Entersomething-->')iflen(s)<3:raiseShortInputException(len(s),3)else:print(s)exceptEOFError:print'\nWhydidyoudoanEOFonme?'exceptShortInputExceptionasx:print('ShortInputException:Theinputwaslength%d,\wasexpectingatleast%d.'%(x.length,x.atleast))else:print('Noexceptionwasraised.')4.7.4自定義異常類(lèi)
在上述例子中,先自定義了一個(gè)名為ShortInputException的異常類(lèi),其用來(lái)判斷用戶輸入的字符串長(zhǎng)度是否滿足要求。在本例子中,其判斷輸入的字符串長(zhǎng)度是否等于大于3個(gè)字符,若不滿足,則拋出該異常。4.7.5with語(yǔ)句
有一些任務(wù),可能事先需要設(shè)置,事后做清理工作。對(duì)于這種場(chǎng)景,Python的with語(yǔ)句提供了一種非常方便的處理方式。一個(gè)很好的例子是文件處理,你需要獲取一個(gè)文件句柄,從文件中讀取數(shù)據(jù),然后關(guān)閉文件句柄。
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 農(nóng)藥店合作合同范本
- 丹麥工作合同范本
- 辦理消防驗(yàn)收合同范本
- 個(gè)人工資合同范本
- 入股公司項(xiàng)目合同范本
- 2024年云浮聯(lián)通招聘考試真題
- 東莞代理記賬合同范本
- 2025東風(fēng)公司全球校園招聘筆試參考題庫(kù)附帶答案詳解
- 買(mǎi)賣(mài)車(chē)訂金合同范本
- 2024年河南濮陽(yáng)工學(xué)院籌建處 引進(jìn)考試真題
- 2024年全球協(xié)作機(jī)器人產(chǎn)業(yè)發(fā)展白皮書(shū)
- 春節(jié)安全生產(chǎn)開(kāi)工第一課培訓(xùn)課件內(nèi)容
- 消防設(shè)施維保過(guò)程風(fēng)險(xiǎn)及保障措施
- 中國(guó)傳統(tǒng)文化非遺文化中國(guó)剪紙介紹2
- 飲酒與糖尿病
- 大學(xué)體育與健康 教案 保?。ò硕五\)4
- 非遺資源數(shù)據(jù)庫(kù)建設(shè)
- 銀屑病診療指南2024
- (高清版)DB43∕T 1734-2020 快開(kāi)門(mén)式壓力容器聯(lián)鎖裝置安全技術(shù)要求
- 2024年安防監(jiān)控系統(tǒng)技術(shù)標(biāo)準(zhǔn)與規(guī)范
- 出生醫(yī)學(xué)證明警示教育培訓(xùn)
評(píng)論
0/150
提交評(píng)論