




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第9章成員訪問、迭代器與生成器學習目標
掌握利用特殊方法實現自定義的成員訪問
掌握迭代器的使用方法
了解生成器的特點,掌握生成器的使用方法熟悉幾種常用內置的可迭代對象及其使用方法22025/3/69.1成員訪問
利用特殊方法實現的自定義成員訪問方式,可以實現一些特殊效果的對象,如以往由系統定義和實現的序列和映射等功能。32025/3/69.1.1基本的序列和映射規則 序列和映射是Python中的基本結構序列是以整數作為索引的結構類型,如列表、字符串等。序列是以鍵值作為索引的結構類型,如字典。 序列和映射基本上是元素(item)的集合,要實現它們的基本行為,不可變對象需要實現2個方法,而可變對象需要實現4個。42025/3/69.1.1基本的序列和映射規則
__len__(self):返回集合包含的項數,對序列來說為元素個數,對映射來說為鍵值對數。
__getitem__(self,key):返回與指定鍵相關聯的值。__setitem__(self,key,value):通過與鍵相關聯的方式存儲值,以便以后能夠使用__getitem__來獲取。__delitem__(self,key):對象的組成部分使用__del__語句時被調用,用于刪除與key相關聯的值。52025/3/69.1.1基本的序列和映射規則序列的鍵為負整數時,從末尾往前數。換而言之,x[-n]與x[len(x)-n]等效。如果鍵的類型不合適(如對序列使用字符串鍵),可能引發TypeError異常。對于序列,如果索引的類型是正確的,但不在允許的范圍內,應引發 IndexError異常。62025/3/6【例9-1】創建一個等差數列創建一個等差數列,且,其中k可由程序輸入確定。72025/3/6defcheck_index(key):ifnotisinstance(key,int):raiseTypeErrorifkey<0:raiseIndexErrorclassArithmeticProgression:
def__init__(self,start=0,step=1):self.start=start
self.step=step
self.changed={}
【例9-1】創建一個等差數列82025/3/6def__getitem__(self,key):
check_index(key)try:returnself.changed[key]exceptKeyError:
returnself.start+key*self.step
def__setitem__(self,key,value):check_index(key)self.changed[key]=values=ArithmeticProgression(1,2) foriinrange(5):print(s[i],end='') print(s[10000])程序的執行情況為:1357920001【例9-2】設計一個簡單的字典類92025/3/6classMyDict:
def__init__(self,data={}):self.__data=datadef__setitem__(self,key,value):self.__data[key]=valuedef__getitem__(self,key):returnself.__data[key]a=MyDict({'red':52,'yellow':49})a['green']=103print(a['red'])程序的執行情況為:529.1.2子類化內置類型 基本的序列與映射協議指定的四個方法可以實現序列和字典的定義,卻只是包含了基本的方法。
實現更加全面的序列或映射方法,可直接進行內置類型的子類化。子類化內置類型的方式比完全重新定義一個類方便,不必為每個方法都單獨進行設計,只對特定方法進行調整即可。102025/3/6【例9-3】設計一個具有引用計數的列表112025/3/6classRefList(list):def__init__(self,*args):super().__init__(*args)self.count=0def__getitem__(self,index):self.count+=1
returnsuper().__getitem__(index)cl=RefList(range(10))print(cl)print(cl.reverse())print(cl)print('count=',cl.count)
print(cl[1]+cl[2]) print('count=',cl.count)foriincl:print(i,end='')【例9-3】設計一個具有引用計數的列表122025/3/6程序的執行情況為:[0,1,2,3,4,5,6,7,8,9]None[9,8,7,6,5,4,3,2,1,0]count=015count=29876543210【例9-4】設計一個具有計算功能的字典132025/3/6classCountableDict(dict):def__init__(self,*args):super().__init__(*args)self.count=0
defsum(self):values=list(self.values())returnsum(values)defaverage(self):returnself.sum()/len(list(self.values()))cd=CountableDict()cd['廣東'],cd['江蘇'],cd['山東'],cd['浙江']=9.73,9.26,7.65,5.62print(cd)print(cd.sum())print(cd.average())程序的執行情況為:{'廣東':9.73,'江蘇':9.26,'山東':7.65,'浙江':5.62}32.268.0659.2迭代器對于數據的處理,往往需要借助于列表、元組等序列數據類型。在Python中一切皆對象,對于迭代方法本身,也可以定義出專門的對象,即迭代器。142025/3/69.2.1可迭代對象把可以通過for...in這類語句迭代讀取每條數據供程序使用的對象稱為可迭代對象(Iterable)。可迭代對象的內部實現通過一個內置的__iter__方法構成,作用是返回一個迭代器對象。152025/3/6>>>fornumin[11,22,33]: print(num,end='')112233>>>forkeyind: print(key,end='')abc>>>forcin'python': print(c,end='')python9.2.1可迭代對象判斷一個對象是否可迭代,使用isinstance()來判斷對象是否是Iterable類的實例。162025/3/6>>>fromcollectionsimportIterable>>>isinstance([],Iterable)True>>>isinstance({},Iterable)True>>>isinstance('abc',Iterable)True>>>isinstance(100,Iterable)False9.2.2迭代器規則
list、tuple等可迭代對象,通過iter()函數獲取這些可迭代對象的迭代器,調用了可迭代對象的__iter__方法。
任何實現了__iter__和__next__方法的對象都是迭代器,其中__iter__返回迭代器自身,__next__返回容器中的下一個值。容器中沒有更多元素時拋出StopIteration異常。172025/3/69.2.2迭代器規則182025/3/6列表x通過iter()方法返回了迭代器iterator,不斷調用next()方法獲取全部數值,直到沒有元素而拋出異常。9.2.2迭代器規則
字符串、列表或元組對象都可用于創建迭代器,而迭代器對象可以使用for…in語句進行遍歷。192025/3/6>>>lst=[1,2,3,4]>>>it=iter(lst)>>>print(next(it))1>>>print(next(it))2>>>forxinit: print(x,end="")34>>>print(next(it)) StopIteration9.2.2迭代器規則以next()函數訪問迭代元素的形式:202025/3/6 importsys lst=[1,2,3,4];it=iter(lst)
whileTrue: try: print(next(it),end='') exceptStopIteration: sys.exit()程序的輸出為:12349.2.2迭代器規則 把一個類作為一個迭代器使用需要在類中實現兩個方法__iter__()與__next__()。
__iter__()方法返回一個特殊的迭代器對象, __next__()方法返回下一個迭代器對象。212025/3/6【例9-5】利用迭代器設計一個等比數列利用迭代器設計一個等比數列 。222025/3/6importsysclassGeometricSeries:
def__init__(self,a0,q,n): self.q=q
self.n=n
self.i=0 self.a0=a0def__iter__(self):self.a=self.a0
returnself 9.2.3創建迭代器232025/3/6def__next__(self):ifself.i<self.n: self.i+=1x=self.aself.a*=self.qreturnxelse:
raiseStopIterationif__name__=='__main__': gs=GeometricSeries(1,5,10) gsiter=iter(gs) forxingsiter:
print(x,end='')9.2.3創建迭代器242025/3/6可迭代對象gs本身是迭代器,該實例可設計為如下的簡化形式,可以得到與以上相同的運行結果。if__name__=='__main__':gs=GeometricSeries(1,5,10)#可迭代對象forxings:#遍歷print(x,end='')程序執行結果如下:15251256253125156257812539062519531259.2.4從迭代器得到序列可以將迭代器轉換為序列,比如可以使用list()函數顯式地將迭代器轉換為列表,或者通過tuple()函數轉換為元組。252025/3/6>>>classTestIterator():value=0def__next__(self):self.value+=1ifself.value>10:raiseStopIterationreturnself.valuedef__iter__(self):returnself9.2.4從迭代器得到序列262025/3/6>>>ti=TestIterator()>>>tiiter=iter(ti)>>>p=list(tiiter) >>>print(p) [1,2,3,4,5,6,7,8,9,10]>>>print(list(tiiter)) []>>>print(tuple(ti))
()9.3生成器生成器屬于一種新型的迭代方式,跟迭代器相比,在某些場合下有很多自身的特點和優勢。用于在遍歷時現場計算和生成序列數值的特殊函數稱為生成器(Generator)。272025/3/69.3生成器函數生成器函數不是通過return語句來返回數值,而是通過yield語句來迭代返回序列的元素。
yield語句每次返回一個值,由生成器函數來保存當前函數的執行狀態,等待下一次調用。
生成器函數返回的是完整的序列,生成器函數本身則屬于一個特殊的迭代器。282025/3/6【例9-6】設計一個求自然數數列3的倍數的生成器函數292025/3/6defgentriples(n):foriinrange(n):yieldi*3f=gentriples(10)i=iter(f)forjinrange(10):
print(next(i),end='')程序執行結果如下:03691215182124279.3.1生成器函數調用生成器函數時,函數返回了一個生成器對象,并沒有執行。當next()方法第一次被調用時,生成器函數開始執行,執行到yield語句處停止,next()方法的返回值就是yield語句處的參數(yieldedvalue)。繼續調用next()方法時,函數接上一次停止的yield語句處繼續執行,并到下一個yield處停止;如果后面沒有yield則拋出StopIteration異常。生成器完全符合迭代器規則,具備對iter()、next()函數的支持能力,同時數據遍歷結束時會拋出StopIteration異常。302025/3/6【例9-7】利用迭代器方法求自然數數列3的倍數312025/3/6classGentriples:def__init__(self,n):self.n=nself.i=0def__iter__(self):returnself
def__next__(self):ifself.i>=self.n:raiseStopIterationt=self.i*3self.i+=1returntforiinGentriples(10):print(i,end='')程序執行結果如下:03691215182124279.3.2反向迭代器將一個序列進行反向輸出,實現方法有多種,如使用列表的reverse()方法、利用序列切片的方法。采用列表的reverse()方法可以實現元素的反向排列,它改變了原有的列表,而成為了反向排列的新列表。322025/3/6>>>lst=[1,2,3,4,5]>>>lst.reverse()>>>foriinx: print(i,end='')543219.3.2反向迭代器序列切片的方法也能夠獲得反向排列的數據,它創建了與原有列表等長的新列表。332025/3/6>>>list1=[1,2,3,4,5]>>>list2=list1[::-1]>>>forxinlist2: print(x,end='')543219.3.2反向迭代器采用生成器的方法可以實現一種新型的反向迭代,它采用一種反向協議的方式,通過定義__reversed__方法,來構成一個反向迭代器。
在使用反向迭代器時,只需要使用reversed()函數就可以利用反向協議輸出其反向排列的元素。342025/3/6【例9-8】利用生成器方法實現可正向和反向計數的計數器352025/3/6classCountdown:def__init__(self,n):self.n=n
def__iter__(n):
n=self.nwhilen>0:yieldnn-=1def__reversed__(self):n=1
whilen<=self.n:
yieldn
n+=1【例9-8】利用生成器方法實現可正向和反向計數的計數器362025/3/6
if__name__=='__main__':c1=Countdown(10)it=iter(c1)
forkinrange(10):print(next(it),end='')print()c2=Countdown(10)foriinc2:print(i,end='')
print()c3=Countdown(10)foriinreversed(c3):print(i,end='') 程序執行結果如下:1098765432110987654321123456789109.3.3推導式以計算的方式來構造序列類型的數據,列表等序列結構,利用一段特定形式的表達式從一個已知序列中的元素計算得到另外一個序列的元素,這種用于序列推導的表達式稱為推導式(Comprehensions),又稱解析式。推導式具有以下的一般形式:
其含義是如果設置了含有變量x的條件表達式,就過濾出符合條件的x,循環得到每個元素x的計算值F(x),形成一個序列。372025/3/6含有變量x的表達式F(x) 含有變量x的for循環[含有變量x的條件表達式]9.3.3推導式
利用推導式可以構建列表、字典和集合,分別稱為列表推導式、字典推導式和集合推導式。
元組是不可變的數據類型,沒有單獨的元組推導式,可運用推導式的方法來構造一個元組。382025/3/69.3.3推導式列表推導式列表推導式符合推導式的一般形式,但需要利用列表的中括號[]來將推導式擴起來,返回的結果是一個列表。392025/3/6>>>la=[iforiinrange(15)] >>>print(la)[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]>>>lb=[i**2foriinla]>>>print(lb)[0,1,4,9,16,25,36,49,64,81,100,121,144,169,196]>>>lc=[i**2foriinlaifi>9andi<16]>>>print(lc)[100,121,144,169,196]9.3.3推導式字典推導式在字典推導式中,表達式F(x)由一個表示鍵的表達式f(x)和一個表示值得表達式g(x)共同構成,中間有一個冒號:,從而構成字典的元素,字典推導式利用大括號{}將推導式擴起來,因此字典推導式的形式為:402025/3/6{f(x):g(x)含有變量x的for循環[含有變量x的條件表達式]}9.3.3推導式對字典元素的鍵按不區分大小寫,將相同字母的鍵所對應的值求和,此外只要求保留其中擁有特定鍵的元素,此處僅保留'a'和'b'兩個鍵。412025/3/6>>>d={'a':11,'b':25,'A':9,'Z':12}>>>dc={ k.lower():d.get(k.lower(),0)+d.get(k.upper(),0)
forkind.keys()
ifk.lower()in['a','b'] }>>>print(dc){'a':20,'b':25}9.3.3推導式將字典的元素中鍵和值對調,形成一個新的字典。422025/3/6>>>d={'a':11,'b':25,'A':9,'Z':12}>>>dc={v:kfork,vind.items()}>>>print(dc){11:'a',25:'b',9:'A',12:'Z'}9.3.3推導式集合推導式
集合推導式符合推導式的一般形式,只是外面由大括號括{}起來,并且返回一個集合。432025/3/6>>>sc={(2*x+1)forxin[2,3,4,1,2,5,6,7,3]}>>>sc{3,5,7,9,11,13,15}9.3.4生成器表達式 將推導式的方法應用于生成器,就是生成器表達式。其推導式的編寫與列表推導式相同,只是外面的大括號[]改為小括號()。 生成器表達式是按需產生一個生成器結果對象,想拿到每一個元素需要循環遍歷。442025/3/6>>>lst=[2,3,4,5]>>>gen=(aforainlst)>>>foriingen: print(i,end='')23459.3.4生成器表達式元組可以利用生成器表達式所得到的生成器,通過tuple()函數進行轉換從而獲得,這種方法也適用于列表、集合等其它方法。452025/3/6>>>g1=(aforainrange(1,6)) >>>print(g1)<generatorobject<genexpr>at0x000002E1F939E938>>>>tuple(g1)(1,2,3,4,5)>>>g2=(aforainrange(5,10))>>>list(g2)[5,6,7,8,9]>>>g3=(x**2forxin[1,1,2,3])>>>set(g3){1,4,9}9.3.4生成器表達式462025/3/6>>>result1=sum(aforainrange(5)) #為生成表達式給出的序列求和,相當于sum((aforainrange(5)))>>>print(result1)10>>>result2=sum([aforainrange(5)])>>>print(result2)10生成器表達式和列表推導式的區別為:
列表推導式比較耗內存生成器表達式幾乎不占用內存,使用的時候才分配和使用內存。9.3.4生成器表達式
生成器本身是迭代器,迭代器一般只是遍歷一次就因拋出StopIteration異常而無法繼續遍歷的特點對于生成器來說也適用472025/3/6>>>defadd(s,x):returns+x>>>defgen():foriinrange(4):yieldi>>>base=gen()>>>x=(add(i,1)foriinbase) >>>print(list(x))[1,2,3,4]>>>y=(add(i,10)foriinbase) >>>print(list(y))9.3.5生成器的方法在生成器開始運行后,可以使用生成器和外部之間的通信渠道向它提供值。
外部程序可訪問生成器的方法send(),將要發送的消息傳遞給生成器的yield語句,并作為其返回值。
當外部程序調用next()函數時,yield語句也能夠獲得返回值,此時返回值為None。482025/3/69.3.5生成器的方法生成器的send()方法具有以下特性:send()方法可以獲取生成器當前yield的值,并促使生成器內的代碼繼續執行,直到下一個yield語句返回了結果并再次掛起生成器內代碼的執行;程序執行時,send()方法之前必須有一個next()函數調用,否則會報錯。第一次調用next()函數之后,調用一次send()方法等同于調用一次next(),都起到繼續執行生成器內序列數據遍歷的作用。492025/3/69.3.5生成器的方法502025/3/6>>>defcount(n):
x=0 whilex<n: value=yieldx print('incount:',value) x+=1>>>x=count(5)>>>print(next(x))0>>>print(x.send('hello'))9.3.5生成器的方法512025/3/6incount:hello1>>>print(x.send('world'))incount:world2>>>print(next(x))incount:None3>>>print(next(x))incount:None49.3.5生成器的方法生成器包含一個close()方法,可以用于根據需要關閉生成器。此時可以在yield處引發GeneratorExit異常。
關閉生成器后,若對生成器再次調用next()函數,由于生成器的迭代已經終止,會得到StopIteration異常。522025/3/69.3.5生成器的方法532025/3/6>>>defRangeStep():
try:print('MyGeneratorstart')foriinrange(0,100,5):
yieldiexceptGeneratorExit:print('Generatorexited')>>>g=RangeStep()MyGeneratorstart>>>forkinrange(10): print(next(g),end='')051015202530354045>>>g.close()
Generatorexited>>>print(next(g)) StopIteration9.3.6生成器的嵌套
yieldfrom語句,可以返回列表、元組等可迭代對象或range()函數產生的序列,也可以返回另一個子生成器。
本質上,yieldfromiterable語句相當于foriteminiterable:yielditem542025/3/69.3.5生成器的方法552025/3/6defgenerator1():forxinrange(3):yieldx**2defgenerator2():yield'a'yield'b'yield'c'yieldfromgenerator1()yieldfrom(x**2forxinrange(3,6))yieldfrom(101,102,104)yieldfrom[201,202,204]yieldfromrange(300,303)foriingenerator2():print(i,end=',')程序運行結果如下:a,b,c,0,1,4,9,16,25,101,102,104,201,202,204,300,301,302,9.4內置的可迭代對象
map映射迭代器filter過濾迭代器
zip組合迭代器
enumerate枚舉迭代器562025/3/69.4.1map映射迭代器
map映射迭代器(簡稱map映射器),來源于map()函數的返回值,會根據提供的函數對指定序列做映射,并形成映射數據構成的可迭代對象。
map函數的格式為map(function,*iterable),可以利用參數列表中的函數function將可迭代對象iterable中的每個元素進行迭代處理,最終形成一個具有迭代器屬性的map對象。572025/3/69.4.1map映射迭代器582025/3/6Traceback(mostrecentcalllast):File"<pyshell#43>",line1,in<module>print(next(it))StopIteration>>>importoperator>>>b=map(operator.add,(1,2,3),(4,5,6))>>>print(tuple(b))(5,7,9)>>>print(list(map(operator.mul,(1,2,3),(1,2,3))))[1,4,9]9.4.2filter映射迭代器 通過filter()函數的使用可以返回一個filter過濾迭代器(簡稱filter過濾器),其目的是用于過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。
filter(function,iterable)函數中,可迭代對象iterable中的每個元素要通過函數function進行鑒別,返回True或False,將返回True的元素放入返回值的可迭代對象之中。592025/3/69.4.2filter映射迭代器602025/3/6>>>defis_odd(n):returnn%2==1>>>x=filter(is_odd,[1,2,3,4,5,6,7,8,9,10])>>>print(x)<filterobjectat0x0000018AF7529358>>>>fromcollectionsimportIterable>>>isinstance(x,Iterable)True>>>foriinx: print(i,end='')13579>>>list(x)[]9.4.2filter映射迭代器出于簡潔和方便的考慮,可以直接采取lambda表達式的方式簡化函數編寫的形式。對于filter過濾器,如果function為None,會返回元素值為True的元素。612025/3/6>>>list(map(lambdax:x**2+1,(1,-1,2,-2))) [2,2,5,5]>>>list(filter(lambdax:x>0,(-1,2,-3,0,5)))[2,5]>>>tuple(filter(None,(1,2,3,0,-1,-2,[],{},(),(5,6))))(1,2,3,-1,-2,(5,6))9.4.3zip組合迭代器
zip()函數的主要作用是將多個可迭代對象(中的對應元素逐一組合,形成的zip對象就構成了新的迭代器,即zip組合迭代器(簡稱zip組合器)。組合方式按照迭代器參數的順序,每次從各個迭代器中分別取一個值作為新迭代器的內容。
每個組合都是以元組的形式保存,最終多個元組形成一個新的序列和可迭代對象。622025/3/69.4.3zip組合迭代器632025/3/6>>>countries=['America','Russa','China','Fance']>>>countries=['America','Russia','China','France']>>>cities=['Newyork','Moscow','Beijing','Paris']>>>forx,yinzip(countries,cities): print('Thecapitalof{}is{}'.format(x,y))ThecapitalofAmericaisNewyorkThecapitalof
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 電動車安全知識宣傳教育
- 全民健康教育知識講座
- 2025屆西平縣三上數學期末預測試題含解析
- 渠縣紅色文化傳承與發展
- 知識產權保護教學課件
- 基礎會計習題及答案
- 工廠電氣安全培訓課件
- 水利水電工程專業知識試題及答案2024
- 在線支付服務協議條款和細則
- 旅游景點規劃與設計知識要點
- ktv入股協議合同范例
- 吸氧并發癥預防及處理
- GB 20943-2025交流-直流和交流-交流電源能效限定值及能效等級
- 民法典下物業服務合同培訓
- 遙感數據質量評價-洞察分析
- 推拿培訓協議合同范例
- 某風電場項目海上升壓站施工組織設計
- 健身器材采購項目投標方案
- Linux操作系統期末復習題(含答案)
- 高考化學一輪復習知識清單:鈉及其重要化合物
- 醫院行風建設教育
評論
0/150
提交評論