Python基礎--迭代器和生成器

1、迭代器

迭代器的特性:

    迭代是Python中最強有力的特性之一,能夠把迭代當作是一種處理序列中元素的方式。

    能夠直接做用於for循環的對象統稱爲可迭代對象(Iterable)。

    能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器(Iterator)。
    
    全部的Iterable都可以經過內置函數iter()來轉變爲Iterator。

    出可迭代對象的個數會報錯StopIteration,是一個結束信號

迭代器的優勢:
    
    一、迭代器提供一種不依賴於索引的取值方式,這樣就能夠遍歷那些沒有索引的對象了(字典、集合、文件)
    二、迭代器和列表比較,迭代器是惰性計算,更節約內存

迭代器的缺點:
    一、永遠不能獲取迭代器的長度,使用不如列表索引取值靈活
    二、一次性的,只能日後取值,不能往前,不能像索引同樣取得指定位置的值

2、查看可迭代和迭代器的方法

from collections import Iterable,Iterator
        s='hello'
        l=[1,2,3]
        t=(1,2,3)
        d={'a':1}
        set1={1,2,3,4}
        f=open('a.txt')

        #都是可迭代,只要對象有__iter__()方法,都是可迭代的
        s.__iter__()
        l.__iter__()
        t.__iter__()
        d.__iter__()
        set1.__iter__()
        f.__iter__()
               
        #查看是否能夠迭代的
        print(isinstance(s,Iterable))

        #查看是不是迭代器,只有文件是迭代器
        f.__next__()

        print(isinstance(f,Iterator))

3、手動訪問迭代器中的元素

一、問題

咱們要處理某個可迭代對象中的元素,可是基於某種緣由不能也不想使用for循環。

二、解決方案

要手動訪問可迭代對象中的元素,可使用next()函數,而後本身編寫代碼來捕獲stopiteration異常。例如:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
with open('passwd','r',encoding='utf8') as f:
    while True:
        try:
            line=next(f)
            print(line,end='')
        except StopIteration:
            break
#通常來講,stopiteration異常是用來通知咱們迭代結束的,可是,若是是手動執行next(),也能夠命令他返回一個值,好比None,示例以下:


with open('passwd','r',encoding='utf8') as f:
    while True:
        line=next(f,None)
        if line is None:
            break
        print(line,end='')
大多數狀況下,咱們會用for循環來訪問可迭代對象中的元素,可是,偶爾也會碰到須要對底層迭代機制作更精細狀況的控制。所以,瞭解迭代實際發生了些什麼是頗有必要的。for 循環也是先使用iter方法把要循環的對象生成一個迭代器,而後去遍歷這個迭代器,遍歷迭代器裏的每一個元素
>>> items=[1,2,3]
>>> i=iter(items)     #===> i.__iter__()
>>> next(i)           #===> i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

4、生成器

生成器是一個包含yield關鍵字的函數,當它被調用時,在函數中的代碼不會執行,而會返回一個迭代器。每次請求一個值,就會執行生成器中的代碼,直到遇到一個yield或者return語句,yield語句一位着會生成一個值,return語句一位着生成器要中止執行(不在生成任何東西,return語句只有在一個生成器中使用時才能進行無參數調用)換句話說,生成器是由兩部分組成:生成器的函數和生成器的迭代器,生成器的函數使用def定義,包括yield部分,生成器的迭代器是這個函數返回的部分。
def countdown(n):
    print('starting to count from',n)
    while n>0:
        yield n
        n-=1
    print('Done!')
g=countdown(5)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

#執行結果以下
starting to count from 5
5
4
3
2
1

#函數中出現了yield語句,就會把這個函數轉換成生成器。與普通的函數不一樣,生成器只會在響應迭代操做是纔會運行。調用時須要使用next方法才能執行,沒執行一次,當遇到下一個yield時就會中止,下次執行next時,將從當前yield往下執行,知道遇到一個yield
生成器的本質就是一個迭代器,同時也是一個函數,調用的方式和函數相似,yield也至關於函數中的return
    yield和return的區別:return只能返回一次函數就會完全結束,而yield能返回屢次值
yield到底幹了什麼事情:
    一、yield把函數變成生成器(迭代器),把iter和next方法封裝在函數內部
    二、函數在暫停一及繼續下一次運行時的狀態是yield保存

5、協程

from urllib.request import urlopen
def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        next(res)
        return res
    return wrapper

@init
def get():
    while True:
        url=yield
        res=urlopen(url).read()
        print(res)

g=get()  #g是一個迭代器
# next(g) #這裏使用一個init的裝飾器,自動作了next的工做
g.send("http://www.baidu.com")     #使用send把括號內的URL傳遞給yield
g.send('http://www.python.org')
g.send('http://www.163.com')
協程函數,是把yield改成表達式的方式,改過send代替next給yield傳值
e.send於next(e)的區別
    一、若是函數內yield是表達式形式,那麼必須先next(e),讓生成器在第一個yield位置處等着
    二、兩者的共同之處均可以讓函數在上次暫停的位置繼續運行,不同的地方在於,send在觸發一下次代碼的執行時,給yield傳值
相關文章
相關標籤/搜索