最近在看Python基礎(chǔ)教程(第三版),是之前python課的課本,但是之前沒讀過,雖然python一直用得挺多,但重新讀讀收獲還挺大。這里做個筆記。
先是迭代器是什么并簡單實現(xiàn)一個迭代器,然后是實現(xiàn)了一些range()。后面本來想寫生成器和八皇后問題,但是發(fā)現(xiàn)了一些很不錯的博客,比我能寫出來的好多了,把鏈接收藏在后面了。
創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站、網(wǎng)站重做改版、十堰鄖陽網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、成都做商城網(wǎng)站、集團公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為十堰鄖陽等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
? 迭代器是像循環(huán)一樣重復(fù)很多次,但不會像列表那樣一次性全部生成,而是需要用的時候再生成,就節(jié)省了內(nèi)存資源。有時可能只想一個個地獲取值,而不是用列表一次性獲取,列表可能占用太多內(nèi)存,并且有時沒辦法使用列表,列表的長度會到無窮大。
簡單的說,迭代器類中:
根據(jù)上面描述可以簡單寫一個迭代器出來
class TestIterator:
value = 0
def __next__(self):
self.value += 1
if self.value > 10: # 到這個條件了沒有可返回的了就拋出一個StopIteration異常
raise StopIteration
return self.value # 每次返回下一個
def __iter__(self): # 這里返回它自己
return self
if __name__ == '__main__':
ti = TestIterator()
print(list(ti))
運行的結(jié)果是:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
嗯于是就能知道了,關(guān)于__iter__和__next__:
實現(xiàn)了方法__iter__的對象是可迭代的,而實現(xiàn)了方法__next__的對象是迭代器。
方法__iter__返回一個迭代器,它是包含方法__next__的對象。
文檔中也寫得很清楚了,調(diào)用__next__時,迭代器應(yīng)返回其下一個值。如果迭代器沒有可供返回的值,則引發(fā)StopIteration異常。
iter返回一個迭代器對象,即object.__iter__()。如果指定了sentinel(哨兵),這個迭代器將不斷調(diào)用直到返回的是sentinel。
然后再來一個斐波那契數(shù)列的例子,迭代器對象可以被放進for循環(huán)。
class Fibs:
def __init__(self) -> None:
self.a = 0
self.b = 1
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
def __iter__(self):
return self
if __name__ == '__main__':
fibs = Fibs()
for f in fibs: # 首先會執(zhí)行__iter__方法獲取返回值,就它自己,然后執(zhí)行一次它的__next__方法,不斷循環(huán)。
if f > 1000:
print(f)
break
返回這個數(shù)列中第一個大于1000的數(shù),是1597。
(base) eisen@pop-os:~$ python3.8
Python 3.8.10 (default, Mar 15 2022, 12:22:08)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> v1 = range(20)
>>> dir(v1)
['__bool__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index', 'start', 'step', 'stop']
這里先看到v1里面只有__iter__,v1為可迭代對象Iterable,讓v2 = v1.__iter__()
>>> v2 = v1.__iter__()
>>> dir(v2)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
可以看到v2既有__iter__又有__next__為迭代器對象。range就是執(zhí)行v1的__iter__獲取到里面的迭代器對象v2,再執(zhí)行v2的__next__方法...
>>> v2.__next__()
0
>>> v2.__next__()
1
>>> v2.__next__()
2
>>> v2.__next__()
3
>>> v2.__next__()
4
>>> v2.__next__()
5
到這里就能理解書上這段話了。
于是實現(xiàn)一下range就很簡單了,在實現(xiàn)的MyRange里面,__iter__方法就生成一個IterRange類的迭代器對象。
class IterRange():
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 MyRange():
def __init__(self, num):
self.num = num
def __iter__(self):
return IterRange(self.num)
v1 = MyRange(20)
for i in v1:
print(i)
輸出就是把0到19打印出來。
本來還想寫后面的生成器和八皇后問題,但是發(fā)現(xiàn)了一些很不錯的博客,我就沒必要自己寫了。這里收藏一下。
Python中生成器的原理,這一篇講了生成器的使用方法,和詳細的原理(里面有源碼)
深入理解Python中的生成器,這一篇寫了生成器的語法,以及它支持的方法close/send等。
python生成器和迭代器有這篇就夠了,這篇寫得很詳細,后面還有補充itertools庫的學(xué)習(xí)。
還記得八皇后的解法嗎,這篇講了個故事。