高級特性

迭代

  • 使用for循環(huán)時,只要作用于一個可迭代對象,for循環(huán)就可以正常運行

  • 如何判斷一個對象是可迭代對象 ?
    通過collections模塊的Iterable類型判斷:

>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整數(shù)是否可迭代
False
  • Python內(nèi)置的enumerate函數(shù)可以把一個list變成索引-元素對,這樣就可以在for循環(huán)中同時迭代索引和元素本身:
>>> for i, value in enumerate(['A', 'B', 'C']):
...     print(i, value)
...
0 A
1 B
2 C

生成器

通過列表生成式,我們可以直接創(chuàng)建一個列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費了。

所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。在Python中,這種一邊循環(huán)一邊計算的機(jī)制,稱為生成器:generator。

要創(chuàng)建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就創(chuàng)建了一個generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

創(chuàng)建L和g的區(qū)別僅在于最外層的[]和(),L是一個list,而g是一個generator。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

這就是定義generator的另一種方法。如果一個函數(shù)定義中包含yield關(guān)鍵字,那么這個函數(shù)就不再是一個普通函數(shù),而是一個generator:

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

這里,最難理解的就是generator和函數(shù)的執(zhí)行流程不一樣。函數(shù)是順序執(zhí)行,遇到return語句或者最后一行函數(shù)語句就返回。而變成generator的函數(shù),在每次調(diào)用next()的時候執(zhí)行,遇到y(tǒng)ield語句返回,再次執(zhí)行時從上次返回的yield語句處繼續(xù)執(zhí)行。

迭代器

我們已經(jīng)知道,可以直接作用于for循環(huán)的數(shù)據(jù)類型有以下幾種:

一類是集合數(shù)據(jù)類型,如list、tuple、dict、set、str等;

一類是generator,包括生成器和帶yield的generator function。

這些可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象:Iterable。

可以使用isinstance()判斷一個對象是否是Iterable對象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但可以作用于for循環(huán),還可以被next()函數(shù)不斷調(diào)用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續(xù)返回下一個值了。

可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator。

可以使用isinstance()判斷一個對象是否是Iterator對象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator。

把list、dict、str等Iterable變成Iterator可以使用iter()函數(shù):

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能會問,為什么list、dict、str等數(shù)據(jù)類型不是Iterator?

這是因為Python的Iterator對象表示的是一個數(shù)據(jù)流,Iterator對象可以被next()函數(shù)調(diào)用并不斷返回下一個數(shù)據(jù),直到?jīng)]有數(shù)據(jù)時拋出StopIteration錯誤??梢园堰@個數(shù)據(jù)流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數(shù)實現(xiàn)按需計算下一個數(shù)據(jù),所以Iterator的計算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才會計算。

Iterator甚至可以表示一個無限大的數(shù)據(jù)流,例如全體自然數(shù)。而使用list是永遠(yuǎn)不可能存儲全體自然數(shù)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.切片切片可以取list、tuple、string的元素python語言中把字符串看做一個tuple,因此可以通...
    JEZAU閱讀 474評論 1 2
  • 一.流程控制 學(xué)習(xí)Demo 1.1 if 語句 可能會有零到多個 elif 部分,else 是可選的。關(guān)鍵字 ‘e...
    小哥_xiaoge閱讀 405評論 0 1
  • !/usr/bin/env python3 -*- coding:utf-8 -*- 三、高級特性 '''在Pyt...
    魚得閱讀 210評論 0 1
  • 一.函數(shù) 1.1 調(diào)用函數(shù): Python內(nèi)置了很多有用的函數(shù),我們可以直接調(diào)用。要調(diào)用一個函數(shù),需要知道...
    Mr_dvbkhm閱讀 887評論 0 1
  • 1.切片:取一個list或tuple的部分元素是非常常見的操作,比如說取list中的前n個元素,我們用循環(huán)來實現(xiàn)這...
    4everwrf閱讀 204評論 0 1

友情鏈接更多精彩內(nèi)容