Python3學習筆記(十四):可迭代對象、迭代器和生成器


記得在剛開始學Python的時候,看到可迭代對象(iterable)、迭代器(iterator)和生成器(generator)這三個名詞時,完全懵逼了,根本就不知道是啥意識。現在以自己的理解來詳解下這三者的關系。

一、可迭代對象(iterable)


 

我們知道,在Python世界里,一切皆對象。對象根據定義的維度,又可以分為各種不同的類型,比如:文件對象,字符串對象,列表對象。。。等等。

那什么對象才能叫做可迭代對象呢?一句話:“實現了__inter__方法的對象就叫做可迭代對象”,__inter__方法的作用就是返回一個迭代器對象。直觀理解就是能用for循環進行迭代的對象就是可迭代對象。比如:字符串,列表,元祖,字典,集合等等,都是可迭代對象。

for循環與__inter()__方法又有什么關系呢?

比如我們在對一個列表進行迭代時,如下代碼:

x = [1,2,3]
for i in x:
    print(i)

實際執行情況如下圖:

  • 調用可迭代對象的__inter__方法返回一個迭代器對象(iterator)
  • 不斷調用迭代器的__next__方法返回元素
  • 知道迭代完成后,處理StopIteration異常

二、迭代器(iterator)


 

那么什么叫迭代器呢?它是一個帶狀態的對象,他能在你調用next()方法的時候返回容器中的下一個值,任何實現了__iter____next__()方法的對象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一個值,如果容器中沒有更多元素了,則拋出StopIteration異常。

根據定義,我們可以寫一個迭代器,並通過next()方法來調用,如下代碼:

class Fib():
    def __init__(self,max):
        self.n = 0
        self.prev = 0
        self.curr = 1
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if self.n < self.max:
            value = self.curr
            self.curr += self.prev
            self.prev = value
            self.n += 1
            return value
        else:
            raise StopIteration

# 調用
f = Fib(5)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))

執行結果:

"C:\Program Files\Python36\python.exe" D:/Git/Test_Framework/utils/1.py
1
1
2
3
5
Traceback (most recent call last):
  File "D:/Git/Test_Framework/utils/1.py", line 37, in <module>
    print(next(f))
  File "D:/Git/Test_Framework/utils/1.py", line 29, in __next__
    raise StopIteration
StopIteration

Process finished with exit code 1

迭代器就像一個懶加載的工廠,等到有人需要的時候才給它生成值返回,沒調用的時候就處於休眠狀態等待下一次調用。直到無元素可調用,返回StopIteration異常。

三、生成器(generator)


 

生成器其實是一種特殊的迭代器,不過這種迭代器更加優雅。它不需要再像上面的類一樣寫__iter__()__next__()方法了,只需要一個yiled關鍵字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一種懶加載的模式生成值。用生成器來實現斐波那契數列的例子是:

def fib(max):
    n, prev, curr = 0, 0, 1
    while n<max:
        yield curr
        prev, curr = curr, curr + prev
        n += 1

生成器特殊的地方在於函數體中沒有return關鍵字,函數的返回值是一個生成器對象。當執行f=fib()返回的是一個生成器對象,此時函數體中的代碼並不會執行,只有顯示或隱示地調用next的時候才會真正執行里面的代碼。

生成器還有一個send方法,可以往生成器里的變量傳值,如下代碼:

def foo():
    print("first")
    count=yield
    print(count)
    yield

f = foo()
f.send(None)
f.send(2)

調用過程:

  1. f = foo()返回一個生成器
  2. f.send(None)進入函數執行代碼,遇到count=yield,凍結並跳出函數體
  3. f.send(2)再次進入函數體,接着凍結的代碼繼續執行,把2傳給變量count,打印count,遇到yield凍結並跳出函數

四、生成器表達式(generator expression)


 

生成器表達式是列表推倒式的生成器版本,看起來像列表推導式,但是它返回的是一個生成器對象而不是列表對象。

a = (x for x in range(10))
print(a)

執行結果:

"C:\Program Files\Python36\python.exe" D:/Git/Test_Framework/utils/1.py
<generator object <genexpr> at 0x000000000289D8E0>

Process finished with exit code 0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM