class A():
def __init__(self):
self.num = 1
def __call__(self):
x = self.num
self.num += 1
return x
a = A()
b = iter(a,5)
from collections import Iterable,Iterator
#我們可以看到a對(duì)象既不是可迭代對(duì)象也不是迭代器,但通過(guò)iter()方法返回的對(duì)象b確實(shí)迭代器
isinstance(a,Iterable) >>> False
isinstance(a,Iterator) >>> False
isinstance(b,Iterator) >>> True
isinstance(b,Iterable) >>> True
#通過(guò)for...in循環(huán)遍歷打?。看窝h(huán)都調(diào)用__call__()方法,直至返回值等于5,觸發(fā)StopIteration停止迭代)
for i in b:
print(i) >>> 1 2 3 4
#iter()的第二種形式的一個(gè)有用的應(yīng)用是構(gòu)建塊讀取器。例如,從二進(jìn)制數(shù)據(jù)庫(kù)文件中讀取固定寬度的塊,直到到達(dá)文件結(jié)尾:
from functools import partial
with open('mydata.db', 'rb') as f:
for block in iter(partial(f.read, 64), b''):
process_block(block)
2.直接調(diào)用可迭代對(duì)象的__iter__方法;
#定義__iter__()方法,可以返回自己,但自己要定義__next__()方法;也可以返回其他對(duì)象的迭代器
#第一種:返回自身,同時(shí)定義自身的__next__()方法
class A():
def __init__(self):
pass
def __iter__(self):
self.num = 0
return self
def __next__(self):
if self.num 10:
N = self.num
self.num += 1
return N
else:
raise StopIteration
a = A()
b = a.__iter__()
from collections import Iterable,Iterator
#由于A類(lèi)中我們定義的__iter__()函數(shù)是返回自己,同時(shí)定義了自身的__next__()方法,所以對(duì)象a既是可迭代對(duì)象,又是迭代器。
isinstance(a,Iterable) >>> True
isinstance(a,Iterator) >>> True
#同時(shí)我們可以看到對(duì)象a經(jīng)過(guò)iter()方法后生成的b對(duì)象是迭代器。
isinstance(b,Iterable) >>> True
isinstance(b,Iterator) >>> True
#第二種:返回其他對(duì)象的迭代器
class A():
def __init__(self):
pass
def __iter__(self):
self.num = 0
return b
class B(A):
def __next__(self):
if self.num 10:
N = self.num
self.num += 1
return N
else:
raise StopIteration
#實(shí)例化兩個(gè)對(duì)象:a和b,當(dāng)調(diào)用對(duì)象a的__iter__()方法時(shí),返回對(duì)象b,B繼承于A類(lèi),所以b對(duì)象是一個(gè)迭代器。
a = A()
b = B()
#調(diào)用a的__iter__()方法
c = a.__iter__()
from collections import Iterable,Iterator
#由于對(duì)象a不具備__next__()方法,因此僅僅是一個(gè)可迭代對(duì)象
isinstance(a,Iterable) >>> True
isinstance(a,Iterator) >>> False
#但是調(diào)用對(duì)象a的__iter()方法生成的c,同時(shí)具備__iter__()和__next__()方法,是一個(gè)迭代器。
isinstance(c,Iterable) >>> True
isinstance(c,Iterator) >>> True
#iter()函數(shù):其運(yùn)行機(jī)制是尋找對(duì)象中的__iter__()方法,運(yùn)行并返回結(jié)果,如果__iter__()方法返回的不是迭代器,則此方法會(huì)報(bào)錯(cuò);如果沒(méi)有此方法,則尋找__getitem__()方法。
class A():
def __init__(self):
pass
def __iter__(self):
return 1 #我們知道數(shù)字1不是迭代器,此函數(shù)返回的是一個(gè)非迭代器
a = A()
b = iter(a)
Traceback (most recent call last):
File "input>", line 10, in module>
TypeError: iter() returned non-iterator of type 'int'
#直接調(diào)用__iter__()方法:如果想通過(guò)調(diào)用此方法生成迭代器,只能定義在此函數(shù)下返回一個(gè)迭代器;如果定義返回的不是迭代器,調(diào)用此方法是不會(huì)生成迭代器的。
class A():
def __init__(self):
pass
def __iter__(self):
return 1
a = A()
#直接調(diào)用__iter__()方法
b = a.__iter__()
#我們可以看到返回的是1,而不是迭代器,只有當(dāng)你定義返回迭代器時(shí),調(diào)用此方法才會(huì)返回迭代器
print(b) >>> 1
#我們定義一個(gè)類(lèi):具有__iter__()方法,但返回的不是迭代器
class A():
def __init__(self):
pass
def __iter__(self):
return 1
a = A()
from collections import Iterable
#我們使用isinstance()結(jié)合collections看一下:會(huì)發(fā)現(xiàn)此方法認(rèn)為他是一個(gè)可迭代對(duì)象
isinstance(a,Iterable) >>> True
#我們使用for...in進(jìn)行循環(huán)訪(fǎng)問(wèn),發(fā)現(xiàn)并不能
for i in a:
print(i)
Traceback (most recent call last):
File "input>", line 1, in module>
TypeError: iter() returned non-iterator of type 'int'
#接下來(lái),我們?cè)俣x一個(gè)類(lèi):具有__iter__()方法和__next__()方法,但返回的不是迭代器
class A():
def __init__(self):
pass
def __iter__(self):
pass
def __next__(self):
pass
a = A()
from collections import Iterator
#我們使用isinstance()結(jié)合collections看一下:會(huì)發(fā)現(xiàn)此方法認(rèn)為他是一個(gè)迭代器
isinstance(a,Iterator) >>> True
#我們使用for...in進(jìn)行循環(huán)訪(fǎng)問(wèn),發(fā)現(xiàn)并不能
for i in a:
print(a)
Traceback (most recent call last):
File "input>", line 1, in module>
TypeError: iter() returned non-iterator of type 'NoneType'
2.使用iter()內(nèi)置函數(shù)進(jìn)行判斷:
class A():
def __init__(self):
pass
def __iter__(self):
return 1
a = A()
#使用iter()函數(shù)如果報(bào)錯(cuò),則不是可迭代對(duì)象,如果不報(bào)錯(cuò),則是可迭代對(duì)象
b = iter(a)
Traceback (most recent call last):
File "input>", line 1, in module>
TypeError: iter() returned non-iterator of type 'int'
3.使用for…in方法進(jìn)行遍歷,如果可以遍歷,即為可迭代對(duì)象
#for...in循環(huán)的實(shí)質(zhì)是:先調(diào)用對(duì)象的__iter__()方法,返回一個(gè)迭代器,然后不斷的調(diào)用迭代器的__next__()方法。
class A():
def __init__(self):
pass
def __iter__(self):
self.num = 0
return self
def __next__(self):
if self.num 10:
N = self.num
self.num += 1
return N
else:
raise StopIteration
a = A()
for i in a:
print(i) >>> 0 1 2 3 4 5 6 7 8 9
#等同于:先調(diào)用對(duì)象的__iter__()方法,返回一個(gè)迭代器,然后不斷的調(diào)用迭代器的__next__()方法,調(diào)用完返回StopIteration,結(jié)束迭代
b = iter(a)
while True:
try:
next(b)
except:
raise StopIteration
0 1 2 3 4 5 6 7 8 9
Traceback (most recent call last):
File "stdin>", line 3, in module>
File "stdin>", line 13, in __next__
StopIteration
def A():
yield 1
yield 2
a = A()
print(a)
#可以看出a顯示的是一個(gè)生成器對(duì)象
generator object A at 0x7f4f94409eb8>
#我們使用dir()函數(shù)看一下生成器的方法:
dir(a)
['省略', '__iter__', '省略', '__next__', 'send', 'throw','省略']
#可以看到生成器里面自動(dòng)完成了對(duì)__iter__()和__next__()方法的定義
#我們調(diào)用對(duì)象的__iter__()方法
print(iter(a)) >>> generator object A at 0x7f4f94409eb8>
print(a) >>> generator object A at 0x7f4f94409eb8>
#可以看到,調(diào)用__iter__()方法,返回的是對(duì)象自己
#我們調(diào)用對(duì)象的__next__()方法
next(a) >>> 1
#可以看到,再次調(diào)用next()方法,是在上次的基礎(chǔ)上繼續(xù)運(yùn)行的,返回的是2,而不是像普通函數(shù)一樣,從頭開(kāi)始重新運(yùn)行
next(a) >>> 2
next(a)
Traceback (most recent call last):
File "stdin>", line 1, in module>
StopIteration
#可以看到生成器a調(diào)用next()方法后生成下一個(gè)元素,同時(shí)當(dāng)元素耗盡時(shí),拋出StopIteration錯(cuò)誤,這和迭代器完全相似
#生成器完全符合迭代器的要求,所以生成器也屬于迭代器
除了定義一個(gè)yield函數(shù)外,還可以利用推導(dǎo)式生成一個(gè)生成器
#一般的推導(dǎo)式有列表推導(dǎo)式和字典推導(dǎo)式,與兩者不同,生成器的推導(dǎo)式是寫(xiě)在小括號(hào)中的,而且只能是比較簡(jiǎn)單的生成器,比較復(fù)雜的生成器一般是寫(xiě)成yield函數(shù)的形式.
a = (i for i in range(5))
print(a)
generator object genexpr> at 0x03CFDE28>
類(lèi)型
定義
判斷方法
生成器
使用yield的函數(shù),或者類(lèi)似(i for i in range(5))這樣的推導(dǎo)式,自動(dòng)實(shí)現(xiàn)__iter__()和__next__()方法