最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

3.0 Python 迭代器與生成器

2023-08-22 12:53 作者:bili_42682284418  | 我要投稿

當(dāng)我們需要處理一個(gè)大量的數(shù)據(jù)集合時(shí),一次性將其全部讀入內(nèi)存并處理可能會(huì)導(dǎo)致內(nèi)存溢出。此時(shí),我們可以采用迭代器Iterator和生成器Generator的方法,逐個(gè)地處理數(shù)據(jù),從而避免內(nèi)存溢出的問(wèn)題。

迭代器是一個(gè)可以逐個(gè)訪問(wèn)元素的對(duì)象,它實(shí)現(xiàn)了python的迭代協(xié)議,即實(shí)現(xiàn)了__iter__()__next__()方法。通過(guò)調(diào)用__next__()方法,我們可以逐個(gè)訪問(wèn)迭代器中的元素,直到所有元素都被訪問(wèn)完畢,此時(shí)再次調(diào)用__next__()方法會(huì)引發(fā)StopIteration異常。

生成器是一種特殊的迭代器,它的實(shí)現(xiàn)方式更為簡(jiǎn)潔,即通過(guò)yield語(yǔ)句來(lái)實(shí)現(xiàn)。生成器函數(shù)使用yield語(yǔ)句返回值,當(dāng)生成器函數(shù)被調(diào)用時(shí),它會(huì)返回一個(gè)生成器對(duì)象,通過(guò)調(diào)用__next__()方法來(lái)逐個(gè)訪問(wèn)生成器中的元素,直到所有元素都被訪問(wèn)完畢,此時(shí)再次調(diào)用__next__()方法會(huì)引發(fā)StopIteration異常。

使用迭代器和生成器可以有效地避免內(nèi)存溢出問(wèn)題,并且代碼實(shí)現(xiàn)也更為簡(jiǎn)潔、高效。在python中,很多內(nèi)置函數(shù)和語(yǔ)言特性都支持迭代器和生成器的使用,例如for循環(huán)、列表推導(dǎo)式、生成器表達(dá)式等。

3.1 使用迭代器

迭代器可以通過(guò)內(nèi)置函數(shù)iter()進(jìn)行創(chuàng)建,同時(shí)可以使用next()函數(shù)獲取下一個(gè)元素,如果迭代器沒(méi)有更多的元素,則拋出StopIteration異常在for循環(huán)中,迭代器可以自動(dòng)實(shí)現(xiàn)例如for x in my_iterable:語(yǔ)句就可以遍歷my_iterable對(duì)象的所有元素。此外python中還有一種特殊的迭代器,稱為生成器(generator),生成器是一種用簡(jiǎn)單的方法實(shí)現(xiàn)迭代器的方式,使用了yield語(yǔ)句,生成器在執(zhí)行過(guò)程中可以暫停并繼續(xù)執(zhí)行,而函數(shù)則是一旦開(kāi)始執(zhí)行就會(huì)一直執(zhí)行到返回。

創(chuàng)建基本迭代器:?首先聲明列表,然后使用__iter__將其轉(zhuǎn)為迭代器,并通過(guò)__next__遍歷迭代對(duì)象.

>>>?list?=?[1,2,3,4,5,6,7,8,9,10]
>>>
>>>?item?=?list.__iter__()
>>>?type(item)
<class?'list_iterator'>
>>>
>>>?item.__next__()
1
>>>?next(item)
2

迭代器遍歷日志文件:?使用迭代器可以實(shí)現(xiàn)對(duì)文本文件或日志的遍歷,該方式可以遍歷大型文件而不會(huì)出現(xiàn)卡死現(xiàn)象.

#?手動(dòng)訪問(wèn)迭代器中的元素,可以使用next()函數(shù)
>>>?with?open("passwd.log")?as?fp:
...?????try:
...?????????????while?True:
...?????????????????????print(next(fp))
...?????except?StopIteration:
...?????????????print("none")

#?通過(guò)指定返回結(jié)束值來(lái)判斷迭代結(jié)束
>>>?with?open("passwd.log")?as?fp:
...?????while?True:
...?????????????line?=?next(fp,None)
...?????????????if?line?is?None:
...?????????????????????break
...?????????????print(line)

循環(huán)遍歷迭代元素:?由于迭代器遍歷結(jié)束會(huì)報(bào)錯(cuò),所以要使用try語(yǔ)句拋出一個(gè)StopIteration結(jié)束異常.

>>>?listvar?=?["呂洞賓",?"張果老",?"藍(lán)采和",?"特乖離",?"和香菇",?"漢鐘離",?"王文"]
>>>?item?=?listvar.__iter__()
>>>
>>>?while?True:
...?????try:
...?????????????temp?=?next(item)
...?????????????print(temp)
...?????except?StopIteration:
...?????????????break

迭代器與數(shù)組之間互轉(zhuǎn):?通過(guò)使用enumerate方法,并將列表轉(zhuǎn)為迭代器對(duì)象,然后將對(duì)象轉(zhuǎn)為制定格式.

>>>?listvar?=?["呂洞賓",?"張果老",?"藍(lán)采和",?"特乖離",?"和香菇",?"漢鐘離",?"王文"]
>>>
>>>?iter?=?enumerate(listvar)??#?轉(zhuǎn)換為迭代器
>>>?dict?=?tuple(iter)?????????#?轉(zhuǎn)換為元組
>>>?dict
((0,?'呂洞賓'),?(1,?'張果老'),?(2,?'藍(lán)采和'),?(3,?'特乖離'),?(4,?'和香菇'),?(5,?'漢鐘離'),?(6,?'王文'))
>>>
>>>?dict?=?list(iter)
>>>?dict
[(0,?'呂洞賓'),?(1,?'張果老'),?(2,?'藍(lán)采和'),?(3,?'特乖離'),?(4,?'和香菇'),?(5,?'漢鐘離'),?(6,?'王文')]

3.2 使用生成器

生成器是一種可以動(dòng)態(tài)生成數(shù)據(jù)的迭代器,不同于列表等容器類(lèi)型一次性把所有數(shù)據(jù)生成并存儲(chǔ)在內(nèi)存中,生成器可以在需要時(shí)動(dòng)態(tài)生成數(shù)據(jù),這樣可以節(jié)省內(nèi)存空間和提高程序效率.使用生成器可以通過(guò)for循環(huán)遍歷序列、列表等容器類(lèi)型,而不需要提前知道其中所有元素.生成器可以使用yield關(guān)鍵字返回值,每次調(diào)用yield會(huì)暫停生成器并記錄當(dāng)前狀態(tài),下一次調(diào)用時(shí)可以從上一次暫停的地方繼續(xù)執(zhí)行,而生成器的狀態(tài)則保留在生成器對(duì)象內(nèi)部.除了使用next()函數(shù)調(diào)用生成器外,還可以使用send()函數(shù)向生成器中發(fā)送數(shù)據(jù),并在生成器內(nèi)部使用yield表達(dá)式接收發(fā)送的數(shù)據(jù).

當(dāng)我們調(diào)用一個(gè)生成器函數(shù)時(shí),其實(shí)返回的是一個(gè)迭代器對(duì)象 只要表達(dá)式中使用了yield函數(shù),通常將此類(lèi)函數(shù)稱為生成器(generator) 運(yùn)行生成器時(shí),每次遇到y(tǒng)ield函數(shù),則會(huì)自動(dòng)保存并暫停執(zhí)行,直到使用next()方法時(shí),才會(huì)繼續(xù)迭代 跟普通函數(shù)不同,生成器是一個(gè)返回迭代器的函數(shù),只能用于迭代操作,更簡(jiǎn)單點(diǎn)理解生成器就是一個(gè)迭代器

在學(xué)習(xí)生成器之前,需要一些前置知識(shí),先來(lái)研究一下列表解析,列表解析是python迭代機(jī)制的一種應(yīng)用,它常用于實(shí)現(xiàn)創(chuàng)建新的列表,因此要放置于[]中,列表解析非常靈活,可以用戶快速創(chuàng)建一組相應(yīng)規(guī)則的列表元素,且支持迭代操作.

列表生成式基本語(yǔ)法:?通過(guò)列表生成式,我們可以完成數(shù)據(jù)的生成與過(guò)濾等操作.

>>>?ret?=?[item?for?item?in?range(30)?if?item?>0]
>>>?print(ret)
[1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29]
>>>
>>>?ret?=?[item?for?item?in?range(30)?if?item?>3]
>>>?print(ret)
[4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29]
>>>
>>>?ret?=?[item?for?item?in?range(30)?if?item%2!=0]
>>>?ret
[1,?3,?5,?7,?9,?11,?13,?15,?17,?19,?21,?23,?25,?27,?29]

列表式求階乘:?通過(guò)列表解析式,來(lái)實(shí)現(xiàn)列表的迭代求階乘,并且只打印大于2(if x>=2)的數(shù)據(jù).

>>>?var?=?[1,2,3,4,5]
>>>?retn?=?[?item?**?2?for?item?in?var?]
>>>?retn
[1,?4,?9,?16,?25]
>>>
>>>?retn?=?[?item?**?2?for?item?in?var?if?item?>=?2?]
>>>?retn
[4,?9,?16,?25]
>>>
>>>?retn?=?[?(item**2)/2?for?item?in?range(1,10)?]
>>>?retn
[0.5,?2.0,?4.5,?8.0,?12.5,?18.0,?24.5,?32.0,?40.5]

數(shù)據(jù)轉(zhuǎn)換:?通過(guò)使用列表生成式,實(shí)現(xiàn)將一個(gè)字符串轉(zhuǎn)換成一個(gè)合格的列表.

>>>?String?=?"a,b,c,d,e,f,g,h"
>>>?List?=?[item?for?item?in?String.split(",")]
>>>?List
['a',?'b',?'c',?'d',?'e',?'f',?'g',?'h']

數(shù)據(jù)合并:?通過(guò)列表解析式,實(shí)現(xiàn)迭代將兩個(gè)列表按照規(guī)律合并.

>>>?temp1=["x","y","z"]
>>>?temp2=[1,2,3]
>>>?temp3=[?(i,j)?for?i?in?temp1?for?j?in?temp2?]
>>>?temp3
[('x',?1),?('x',?2),?('x',?3),?('y',?1),?('y',?2),?('y',?3),?('z',?1),?('z',?2),?('z',?3)]

文件過(guò)濾:?通過(guò)使用列表解析,實(shí)現(xiàn)文本的過(guò)濾操作.

>>>?import?os

>>>?file_list=os.listdir("/var/log")
>>>?file_log=[?i?for?i?in?file_list?if?i.endswith(".log")?]
>>>?print(file_log)
['boot.log',?'yum.log',?'ecs_network_optimization.log',?'ntp.log']

>>>?file_log=[?i?for?i?in?os.listdir("/var/log")?if?i.endswith(".log")?]
>>>?print(file_log)
['boot.log',?'yum.log',?'ecs_network_optimization.log',?'ntp.log']

接下來(lái)我們就來(lái)研究一下生成器吧,生成器類(lèi)似于返回值為數(shù)組的一個(gè)函數(shù),這個(gè)函數(shù)可以接受參數(shù),可以被調(diào)用,但不同于一般的函數(shù)會(huì)一次性返回包括了所有數(shù)值的數(shù)組,生成器一次只能產(chǎn)生一個(gè)值,這樣消耗的內(nèi)存數(shù)量將大大減小,而且允許調(diào)用函數(shù)可以很快的處理前幾個(gè)返回值,因此生成器看起來(lái)像是一個(gè)函數(shù),但是表現(xiàn)得卻像是迭代器.

我們先來(lái)看以下兩種情況的對(duì)比,第一種方法很簡(jiǎn)單,只有把一個(gè)列表生成式的[]中括號(hào)改為()小括號(hào),就創(chuàng)建了一個(gè)生成器.

>>>?lis?=?[x*x?for?x?in?range(10)]
>>>?print(lis)
[0,?1,?4,?9,?16,?25,?36,?49,?64,?81]

>>>?generator?=?(x*x?for?x?in?range(10))
>>>?print(generator)
<generator?object?<genexpr>?at?0x0000022E5C788A98>

如上例子,第一個(gè)lis通過(guò)列表生成式,創(chuàng)建了一個(gè)列表,而第二個(gè)generator則打印出一個(gè)內(nèi)存地址,如果我們想獲取到第二個(gè)變量中的數(shù)據(jù),則需要迭代操作,如下所示:

>>>?generator?=?(x*x?for?x?in?range(10))

>>>?print(next(generator))
0
>>>?print(next(generator))
1
>>>?print(next(generator))
4
>>>?print(next(generator))
9

以上可以看到,generator保存的是算法,每次調(diào)用next(generaotr),就計(jì)算出他的下一個(gè)元素的值,直到計(jì)算出最后一個(gè)元素,使用for循環(huán)可以簡(jiǎn)便的遍歷出迭代器中的數(shù)據(jù),因?yàn)間enerator也是可迭代對(duì)象.

>>>?generator?=?(x*x?for?x?in?range(10))
>>>?
>>>?for?i?in?generator:
????print(i,end="")

0149162536496481

生成器表達(dá)式并不真正創(chuàng)建數(shù)字列表,而是返回一個(gè)生成器對(duì)象,此對(duì)象在每次計(jì)算出一個(gè)條目后,把這個(gè)條目"產(chǎn)生"(yield)出來(lái),生成器表達(dá)式使用了"惰性計(jì)算"或稱作"延遲求值"的機(jī)制序列過(guò)長(zhǎng),并且每次只需要獲取一個(gè)元素時(shí),應(yīng)當(dāng)考慮使用生成器表達(dá)式而不是列表解析.

>>>?import?sys
>>>?
>>>?yie=(?i**2?for?i?in?range(1,10)?)
>>>?next(yie)
1
>>>?next(yie)
4
>>>?next(yie)
9

>>>?for?j?in?(?i**2?for?i?in?range(1,10)):print(j/2)

3.3 隊(duì)列的使用

隊(duì)列是一個(gè)多線程編程中常用的數(shù)據(jù)結(jié)構(gòu),它提供了一種可靠的方式來(lái)安全地傳遞數(shù)據(jù)和控制線程間的訪問(wèn). 在多線程環(huán)境下,如果沒(méi)有同步機(jī)制,多個(gè)線程同時(shí)訪問(wèn)共享資源,可能會(huì)導(dǎo)致數(shù)據(jù)混亂或者程序崩潰.而Queue隊(duì)列就是一種線程安全的數(shù)據(jù)結(jié)構(gòu),它提供了多個(gè)線程訪問(wèn)和操作的接口,可以保證多個(gè)線程之間的數(shù)據(jù)安全性和順序性. 通過(guò)Queue隊(duì)列,一個(gè)線程可以將數(shù)據(jù)放入隊(duì)列,而另一個(gè)線程則可以從隊(duì)列中取出數(shù)據(jù)進(jìn)行處理,實(shí)現(xiàn)了線程之間的通信和協(xié)調(diào).

先進(jìn)先出隊(duì)列:?先來(lái)介紹簡(jiǎn)單的隊(duì)列例子,以及隊(duì)列的常用方法的使用,此隊(duì)列是先進(jìn)先出模式.

import?queue

q?=?queue.Queue(5)????????????????????#默認(rèn)maxsize=0無(wú)限接收,最大支持的個(gè)數(shù)
print(q.empty())??????????????????????#查看隊(duì)列是否為空,如果為空則返回True

q.put(1)??????????????????????????????#PUT方法是,向隊(duì)列中添加數(shù)據(jù)
q.put(2)??????????????????????????????#第二個(gè)PUT,第二次向隊(duì)列中添加數(shù)據(jù)
q.put(3,block=False,timeout=2)????????#是否阻塞:默認(rèn)是阻塞block=True,timeout=超時(shí)時(shí)間

print(q.full())???????????????????????#查看隊(duì)列是否已經(jīng)放滿
print(q.qsize())??????????????????????#隊(duì)列中有多少個(gè)元素
print(q.maxsize)??????????????????????#隊(duì)列最大支持的個(gè)數(shù)

print(q.get(block=False,timeout=2))???#GET取數(shù)據(jù)
print(q.get())????????????????????????
q.task_done()???????#join配合task_done,隊(duì)列中有任務(wù)就會(huì)阻塞進(jìn)程,當(dāng)隊(duì)列中的任務(wù)執(zhí)行完畢之后,不在阻塞
print(q.get())
q.task_done()
q.join()????????????#隊(duì)列中還有元素的話,程序就不會(huì)結(jié)束程序,只有元素被取完配合task_done執(zhí)行,程序才會(huì)結(jié)束
import?queue

def?show(q,i):
????if?q.empty()?or?q.qsize()?>=?1:
????????q.put(i)???#存隊(duì)列
????elif?q.full():
????????print('queue?not?size')

que?=?queue.Queue(5)???#允許5個(gè)隊(duì)列的隊(duì)列對(duì)象
for?i?in?range(5):
????show(que,i)
print('queue?is?number:',que.qsize())??#隊(duì)列元素個(gè)數(shù)
for?j?in?range(5):
????print(que.get())??#取隊(duì)列
print('......end')

后進(jìn)先出隊(duì)列:?這個(gè)隊(duì)列則是,后進(jìn)先出,也就是最后放入的數(shù)據(jù)最先彈出,類(lèi)似于堆棧.

>>>?import?queue
>>>
>>>?q?=?queue.LifoQueue()
>>>
>>>?q.put("wang")
>>>?q.put("rui")
>>>?q.put("ni")
>>>?q.put("hao")
>>>
>>>?print(q.get())
hao
>>>?print(q.get())
ni
>>>?print(q.get())
rui
>>>?print(q.get())
wang
>>>?print(q.get())

優(yōu)先級(jí)隊(duì)列:?此類(lèi)隊(duì)列,可以指定優(yōu)先級(jí)順序,默認(rèn)從高到低排列,以此根據(jù)優(yōu)先級(jí)彈出數(shù)據(jù).

>>>?import?queue
>>>
>>>?q?=?queue.PriorityQueue()
>>>
>>>?q.put((1,"python1"))
>>>?q.put((-1,"python2"))
>>>?q.put((10,"python3"))
>>>?q.put((4,"python4"))
>>>?q.put((98,"python5"))
>>>
>>>?print(q.get())
(-1,?'python2')
>>>?print(q.get())
(1,?'python1')
>>>?print(q.get())
(4,?'python4')
>>>?print(q.get())
(10,?'python3')
>>>?print(q.get())
(98,?'python5')

雙向的隊(duì)列:?雙向隊(duì)列,也就是說(shuō)可以分別從兩邊彈出數(shù)據(jù),沒(méi)有任何限制.

>>>?import?queue
>>>
>>>?q?=?queue.deque()
>>>
>>>?q.append(1)
>>>?q.append(2)
>>>?q.append(3)
>>>?q.append(4)
>>>?q.append(5)
>>>
>>>?q.appendleft(6)
>>>
>>>?print(q.pop())
5
>>>?print(q.pop())
4
>>>?print(q.popleft())
6
>>>?print(q.popleft())
1
>>>?print(q.popleft())
2

生產(chǎn)者消費(fèi)者模型:?生產(chǎn)者消費(fèi)者模型,是各種開(kāi)發(fā)場(chǎng)景中最常用的開(kāi)發(fā)模式,以下是模擬的模型.

import?queue,time
import?threading
q?=?queue.Queue()

def?productor(arg):
????while?True:
????????q.put(str(arg))
????????print("%s?號(hào)窗口有票...."%str(arg))
????????time.sleep(1)

def?consumer(arg):
????while?True:
????????print("第?%s?人取?%s?號(hào)窗口票"%(str(arg),q.get()))
????????time.sleep(1)

for?i?in?range(10):?????????????????????#負(fù)責(zé)生產(chǎn)票數(shù)
????t?=?threading.Thread(target=productor,args=(i,))
????t.start()

for?j?in?range(5):??????????????????????#負(fù)責(zé)取票,兩個(gè)用戶取票
????t?=?threading.Thread(target=consumer,args=(j,))
????t1?=?threading.Thread(target=consumer,args=(j,))
????t.start()
????t1.start()

本文作者: 王瑞 本文鏈接: https://www.lyshark.com/post/1c1ebaa1.html 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處!


3.0 Python 迭代器與生成器的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
耿马| 利津县| 来安县| 东莞市| 澎湖县| 万州区| 保靖县| 泽普县| 观塘区| 临沂市| 仁寿县| 泸水县| 伊吾县| 衢州市| 康马县| 凉山| 纳雍县| 高陵县| 铅山县| 米脂县| 临漳县| 仲巴县| 磴口县| 长武县| 博野县| 高唐县| 崇左市| 宽甸| 河曲县| 嵊泗县| 霞浦县| 元谋县| 高清| 亚东县| 玛纳斯县| 普兰县| 静乐县| 枣强县| 沈丘县| 金平| 石家庄市|