迭代器
什么是迭代協(xié)議徒欣?
迭代器是什么打肝?迭代器是訪問集合內(nèi)元素的一種方式颂龙,一般用來遍歷數(shù)據(jù)
迭代器和以下標(biāo)的訪問方式不一樣并鸵。迭代器是不能返回的泰鸡,迭代器提供了一種惰性方式訪問數(shù)據(jù)
任何實(shí)現(xiàn)了iter或者getitem的都是可迭代對(duì)象
class Company(object):
def __init__(self, employee_list):
self.employees = employee_list
def __getitem__(self, item):
return self.employees[item]
company = Company(['張三', '李四', '王五'])
print(isinstance(company, Iterable))
# 執(zhí)行結(jié)果:False
print(isinstance(company, Iterator))
# 執(zhí)行結(jié)果:False
for c in company:
print(c)
執(zhí)行結(jié)果:
張三
李四
王五
對(duì)于for循環(huán)來說,首先尋找iter方法醉锅,如果沒有iter方法硬耍,那么就會(huì)去尋找getitem方法,這個(gè)方法是用來定義序列用的甚纲,
如果兩個(gè)方法都沒有介杆,那么就說這個(gè)對(duì)象是不可迭代的。只要實(shí)現(xiàn)了這兩個(gè)方法中的其中一個(gè)荆隘,就證明這個(gè)對(duì)象是可迭代對(duì)象赴背。
如果有iter方法,就會(huì)得到一個(gè)迭代器對(duì)象燃观,然后調(diào)用迭代器的next方法便瑟,獲取元素脊框,直到拋出StopIteration異常為止浇雹,for循環(huán)本身
會(huì)對(duì)這種異常作出處理箫爷。如果有getitem方法虎锚,那么就從下標(biāo)0開始獲取數(shù)據(jù)窜护。
疑問:只有getitem的類的實(shí)例是屬于可迭代對(duì)象非春,但用isinstances測(cè)試collections.Iterable是不能通過的奇昙,可以通過iter函數(shù)來測(cè)試,
如果沒報(bào)錯(cuò)就說明是可迭代對(duì)象羊初,然后生成一個(gè)沒有next屬性的迭代器晦攒。
print(dir(company))
'''
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'employees']
'''
迭代器需要實(shí)現(xiàn)iter和next,iter用來返回一個(gè)迭代器脯颜,next用來獲取下一個(gè)元素和拋出StopIteration的異常栋操。
備注:內(nèi)置函數(shù)iter()調(diào)用的是iter方法乐设,next()調(diào)用的是next方法
class Company(object):
def __init__(self, employee_list):
self.employees = employee_list
def __iter__(self):
return MyIterator(self.employees)
class MyIterator():
def __init__(self, iter_list):
self.iter_list = iter_list
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
res = self.iter_list[self.index]
except IndexError:
raise StopIteration
self.index += 1
return res
company = Company(['張三', '李四', '王五'])
print(isinstance(company, Iterable))
# 執(zhí)行結(jié)果:True
print(isinstance(company, Iterator))
# 執(zhí)行結(jié)果:False
my_iterator = MyIterator(['張三', '李四', '王五'])
print(isinstance(my_iterator, Iterable))
# 執(zhí)行結(jié)果:True
print(isinstance(my_iterator, Iterator))
# 執(zhí)行結(jié)果:True
for em in company:
print(em)
'''
執(zhí)行結(jié)果
張三
李四
王五
'''
生成器
生成器函數(shù):函數(shù)里面只要有yield關(guān)鍵字蠕啄,那么這就是一個(gè)生成器函數(shù)
生成器函數(shù)最開始調(diào)用的時(shí)候戈锻,返回的是一個(gè)生成器對(duì)象格遭,在python編譯字節(jié)碼的時(shí)候就產(chǎn)生了這個(gè)生成器對(duì)象
生成器函數(shù)也可以return一個(gè)值
生成器函數(shù)會(huì)在內(nèi)部記錄函數(shù)執(zhí)行的字節(jié)碼的位置骚秦,生成器函數(shù)也是分配在堆內(nèi)存當(dāng)中的
調(diào)用生成器函數(shù)作箍,函數(shù)并不會(huì)馬上執(zhí)行胞得,調(diào)用next方法或者用for驅(qū)動(dòng)生成器的執(zhí)行.
如果next方法取不到值了屹电,則要給一個(gè)默認(rèn)值,否則會(huì)報(bào)StopIteration的錯(cuò)誤牧愁。
在生成器函數(shù)中外莲,函數(shù)執(zhí)行遇到y(tǒng)ield會(huì)掛起办龄,返回yield右邊的值,直到下一次生成器再次被驅(qū)動(dòng)俐填。send方法也可以驅(qū)動(dòng)生成器函數(shù)英融。
def foo():
yield 1
name = 'bobby'
yield 2
age = 18
return 30
f = foo()
print(isinstance(f, Generator))
# 執(zhí)行結(jié)果:True
print(next(f))
# 執(zhí)行結(jié)果:1
print(next(f))
# 執(zhí)行結(jié)果:2
print(next(f, 'Over'))
捕獲生成器的返回值
def foo():
yield 1
name = 'bobby'
yield 2
age = 18
return 30
f = foo()
while True:
try:
x = next(f)
print(x)
except StopIteration as e:
print('StopIteration:',e.value)
break
'''
執(zhí)行結(jié)果:
1
2
StopIteration: 30
'''s