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