· 迭代器
什么是迭代器:
迭代器可以讓我們?cè)L問集合的時(shí)候變得非常方便。之前我們通過for…in…來(lái)訪問一個(gè)集合的時(shí)候,就是使用迭代器完成的。
如果沒有迭代器,那么我們只能通過while循環(huán),每次循環(huán)的時(shí)候通過下標(biāo)來(lái)訪問了。
可迭代對(duì)象:
可以直接使用for循環(huán)遍歷的對(duì)象,成為可迭代的對(duì)象,常見的可迭代對(duì)象有:list、tuple、dict、set、str以及生成器
更加專業(yè)的判斷一個(gè)對(duì)象是否是可迭代對(duì)象:這個(gè)對(duì)象有一個(gè)__iter__方法,并且這個(gè)方法會(huì)返回一個(gè)迭代器對(duì)象,這種對(duì)象就叫做可迭代對(duì)象。
判斷一個(gè)對(duì)象是否可迭代:
可以使用is instance()判斷一個(gè)對(duì)象是否是interable對(duì)象
from collections import Iterable
# 列表是一個(gè)可迭代對(duì)象
ret = isinstance([1, 2, 3], Iterable)
print(ret)
字符串是一個(gè)可迭代對(duì)象
ret = isinstance('abc', Iterable)
print(ret)
整形不是一個(gè)可迭代對(duì)象
ret = isinstance(123, Iterable)
print(ret)
迭代器:
1、在python2中,實(shí)現(xiàn)了next和__iter__方法,并且在這個(gè)方法中返回了值的對(duì)象,叫做迭代器對(duì)象
2、在python3中,實(shí)現(xiàn)了__next__方法和__iter__方法,并且在這個(gè)方法中返回了值的對(duì)象,叫做迭代器對(duì)象
3、如果迭代器沒有返回值了,那么應(yīng)該在next或者是__next__方法中拋出一個(gè)StopInteration
使用iter()方法獲取可迭代對(duì)象的迭代器:
有時(shí)候我們擁有了一個(gè)可迭代的對(duì)象,我們想要獲取這個(gè)迭代器,那么可以通過iter(x)方法獲取這個(gè)可迭代對(duì)象
的迭代器。
自定義迭代器:
分開的寫法(方法A):
class MyRangeIterator:
"""
迭代器
"""
def __init__(self, start, end):
self.index = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.index < self.end:
temp = self.index
self.index += 1
return temp
else:
raise StopIteration()
class MyRange:
"""
MyRange是可迭代對(duì)象
"""
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
# 這個(gè)方法中返回一個(gè)迭代器對(duì)象
return MyRangeIterator(self.start, self.end)
if __name__ == '__main__':
myrange = MyRange(1, 10)
for i in myrange:
print(i)
iterator = iter(myrange)
while True:
try:
x = iterator.__next__()
print(x)
except StopIteration:
break
合并到一起的寫法(方法B):
# -*- coding: UTF-8 -*-
from collections import Iterable, Iterator
# Interable: 判斷是否可迭代
# Interator: 判斷是否是迭代器
print(isinstance('abc', Iterable))
print(isinstance('abc', Iterator))
class MyRange:
def __init__(self, start, end):
self.index = start
self.end = end
def __iter__(self):
# 這個(gè)方法要返回一個(gè)迭代器
return self
def __next__(self):
if self.index < self.end:
temp = self.index
self.index += 1
return temp
else:
raise StopIteration()
if __name__ == '__main__':
myrange = MyRange(1, 10)
for i in myrange:
print(i)
for i in myrange:
print(i)
以上兩個(gè)方法,A和B都實(shí)現(xiàn)了迭代器的功能,當(dāng)我們實(shí)例化MyRange時(shí),即獲得了一個(gè)可迭代對(duì)象,在方法A中這個(gè)可迭代對(duì)象返回了一個(gè)迭代器:MyRangeIterator(self.start, self.end),方法B中返回了自己self本身。這時(shí)就會(huì)有一個(gè)區(qū)別產(chǎn)生,因?yàn)锳方法在每次返回迭代器的時(shí)候,都會(huì)實(shí)例化迭代
器,而B中只會(huì)實(shí)例化一次,因此:
myrange = MyRange(1, 10)
for i in myrange:
print(i)
for i in myrange:
print(i)
如果兩個(gè)方法都執(zhí)行上述代碼,A方法每次都會(huì)遍歷出1到9,而B方法只會(huì)遍歷一次,第二次什么都不會(huì)打印。因?yàn)榈诙蝧elf.index 已經(jīng)等于了 self.end。
· 生成器
為什么需要生成器:
當(dāng)我們需要打印一個(gè)1到1億的整形的時(shí)候,如果我們采用普通的方式,直接調(diào)用range函數(shù),程序會(huì)崩潰掉。因?yàn)閞ange(1,100000000)函數(shù)會(huì)直接產(chǎn)生一個(gè)從1-1億的列表,這個(gè)列表中所有數(shù)據(jù)都是存放在內(nèi)存中的,會(huì)導(dǎo)致內(nèi)存爆滿。這時(shí)候我們可以采用生成器來(lái)解決該問題,生成器不會(huì)一次把所有數(shù)據(jù)都加載到內(nèi)存中,而是在循環(huán)的時(shí)候臨時(shí)產(chǎn)生的,循環(huán)一次生成一個(gè),所以程序在運(yùn)行期間永遠(yuǎn)都只會(huì)生成一個(gè)數(shù)據(jù),從而節(jié)省內(nèi)存的開銷。
next函數(shù)和__next__方法:
next函數(shù)可以迭代生成器的返回值
自己寫生成器:
生成器可以通過函數(shù)產(chǎn)生。如果在一個(gè)函數(shù)中出現(xiàn)了yield表達(dá)式,那么這個(gè)函數(shù)將不再是一個(gè)普通的函數(shù),而是一個(gè)生成器函數(shù)。yield一次返回一個(gè)結(jié)果,并且會(huì)凍結(jié)當(dāng)前函數(shù)的狀態(tài)。
普通的列表
num_list = [x for x in range(1, 100)]
print(num_list)
生成式
num_gen = (x for x in range(1, 100))
print(num_gen)
print(type(num_gen))
for i in num_gen:
print(i)
def my_gen():
yield 1
yield 2
yield 3
ret = my_gen()
print(next(ret))
print(next(ret))
print(next(ret))
print(next(ret))
def gen(start, end):
index = start
while index <= end:
yield index
index += 1
生成器有兩個(gè)身份:迭代器和可迭代的對(duì)象, 因此,只能被遍歷一次
ret = gen(1, 100000000)
for i in ret:
print(i)
send方法:
1、也是用來(lái)觸發(fā)代碼,直接碰到y(tǒng)ield表達(dá)式
2、如果用send方法執(zhí)行剛剛開始的生成器,那么應(yīng)該傳遞None給send方法
def my_gen(start):
while start < 10:
# 如果通過next函數(shù)執(zhí)行yield
# 那么yield xxx 永遠(yuǎn)都是返回None
temp = yield start
print(temp)
start += 1
ret = my_gen(1)
第一次使用send方法必須傳None
print(ret.send(None))
print(next(ret))
print(ret.send(‘hello’))
1
None
2
hello
3
send方法和next函數(shù)的區(qū)別:
1、send方法可以傳遞值給yield表達(dá)式,而next不可以
2、在第一次執(zhí)行生成器代碼的時(shí)候,必須要傳None,next則不需要
生成器的一些案例:
def fib(count):
index = 1
a, b = 0, 1
while index <= count:
yield b
c = b
b = a + b
a = c
index +=1
for x in fib(7):
print(x)
#使用生成器 來(lái)實(shí)現(xiàn)多線程,聽音樂和看電影同時(shí)進(jìn)行
def netease_music(duration):
time = 0
while time <= duration:
print('音樂聽了%d分鐘' % time)
time += 1
yield None
# raise StopIteration()
def youku_movie(duration):
time = 0
while time <= duration:
print('電影看了%d分鐘' % time)
time += 1
yield None
# raise StopIteration()
if __name__ == '__main__':
music_iter = netease_music(10)
movie_iter = youku_movie(30)
music_stop = False
movie_stop = False
while True:
try:
next(music_iter)
except StopIteration:
print('音樂聽完了')
music_stop = True
try:
next(movie_iter)
except StopIteration:
print('電影看完了')
movie_stop = True
if music_stop and movie_stop:
break
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
