前言
上次我們簡單分享了迭代器和生成器,本次我們來更加深入的瞭解相關概念和使用方法,希望能對你有所幫助。
自定義迭代器
首先,我們來看看怎麼自定義迭代器,自定義迭代器的類需要下面幾個組成。
(1)類中需要定義iter和next魔術方法。
(2)iter魔術方法返回對象本身。
(3)next方法返回下一個數據,如果沒有數據,就報異常StopIteration。
class Test:
def __init__(self):
self.counter = 0
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == 3:
raise StopIteration
return self.counter
t = Test()
print(next(t))
print(next(t))
print(next(t))
1
2
StopIteration
當然,我們可以直接使用for循環來調用這個迭代器對象。
for i in t:
print(i)
1
2
for循環裏面到底是怎麼執行的了?首先for循環會先調用對象的iter魔術方法,返回一個迭代器對象,然後不斷調用next魔術方法(異常就停止循環)。
生成器
我們之前學習過,函數中有yield關鍵字,那這個函數就是生成器。
def func():
yield 1
yield 2
f = func()
print(next(f))
print(next(f))
1
2
其實這個生成器對象內部其實是調用的生成器類generator創建的對象,生成器類的內部其實也聲明瞭iter和next魔術方法。
生成器也完全符合迭代器聲明的規則,所以,生成器也是一種特殊的迭代器。
可迭代對象
最後,我們再聊聊可迭代對象,我們都知道,列表就是可迭代對象。
l = [1, 2, 3]
for i in l:
print(i)
字符串,字典等等能夠循環的,都是可迭代對象。其定義是,如果類中有iter魔術方法,並且返回的是迭代器對象,那這個類創建的對象就是可迭代對象。
class Test:
def __init__(self):
self.counter = 0
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == 3:
raise StopIteration
return self.counter
class Foo:
def __iter__(self):
return Test()
foo = Foo()
for item in foo:
print(item)
1
2
這裏的foo就是可迭代對象,當使用for循環時,先調用iter魔術方法,返回一個迭代器對象,接着就是不斷的調用next魔術方法返回值。
我們可以驗證下,列表是可迭代對象,那他就應該有iter方法,沒有next方法。
l = [1, 2, 3]
print(dir(l))
#['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
print(dir(l.__iter__()))
調用iter方法後,就會有iter和next方法了。
自定義range函數
學了這麼多,我們來自定義一個range函數來鞏固下學習內容。
class RangeIter:
def __init__(self, num):
self.num = num
self.counter = -1
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == self.num:
raise StopIteration
return self.counter
class Xrange:
def __init__(self, maxnum):
self.maxnum = maxnum
def __iter__(self):
return RangeIter(self.maxnum)
for i in Xrange(10):
print(i)
生成器也可以實現該功能。
class Xrange:
def __init__(self, maxnum):
self.maxnum = maxnum
def __iter__(self):
counter = 0
while counter < self.maxnum:
yield counter
counter += 1
for i in Xrange(5):
print(i)
今天的分享就到這了,我們下期再見~