Python 函數與常用模組 - 叠代器
叠代器
我們已經知道可以直接作用於 for 循環的數據類型有以下幾種:
- 一類是集合數據類型: list 、 tuple 、 dict 、 set 、 str 、 bytes 等。
- 另一類是 generator ,包括生成器和帶 yield 的 generator function。
這些可以直接作用於 for 循環的對象,統稱為可叠代的對象( Iterable ):
可叠代的對象,可以把它想成就是 可以循環的對象
, 可叠代 = 可循環
可以使用 isinstance()
判斷一個對象是否為 Iterable 對象
:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from collections import Iterable print("[] list 列表是否為可叠代對象:", isinstance([], Iterable)) print("() tuple 元組是否為可叠代對象:", isinstance((), Iterable)) print("{} dict 字典是否為可叠代對象:", isinstance({}, Iterable)) print("( x for i in range(10) ) generator 生成器是否為可叠代對象:", isinstance( ( x for i in range(10) ), Iterable)) print("123 數字是否為可叠代對象:", isinstance(123, Iterable)) ---------------執行結果--------------- [] list 列表是否為可叠代對象: True () tuple 元組是否為可叠代對象: True {} dict 字典是否為可叠代對象: True ( x for i in range(10) generator 生成器是否為可叠代對象: True 123 數字是否為可叠代對象: False Process finished with exit code 0
而生成器不但可以作用於 for 循環,還可以被 __next__()
函數不斷地調用並返回下一個值,直到最後拋出 StopIteration 錯誤,表示無法繼續返回下一個值了。
註意,特重要 可以被 __next__() 函數調用,並不斷地返回下一個值的對象
稱為叠代器( Iterator )
可以使用 isinstance()
判斷一個對象是否為 Iterator 對象
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from collections import Iterator print("[] list 列表是否為叠代器:", isinstance([], Iterator)) print("() tuple 元組是否為叠代器:", isinstance((), Iterator)) print("{} dict 字典是否為叠代器:", isinstance({}, Iterator)) print("( x for i in range(10) ) generator 生成器是否為叠代器:", isinstance( ( x for i in range(10) ), Iterator)) print("123 數字是否為叠代器:", isinstance(123, Iterator)) ---------------執行結果--------------- [] list 列表是否為叠代器: False () tuple 元組是否為叠代器: False {} dict 字典是否為叠代器: False ( x for i in range(10) ) generator 生成器是否為叠代器: True 123 數字是否為叠代器: False Process finished with exit code 0
生成器肯定是叠代器,因為有 __next__()
方法, 但叠代器一定是生成器嗎?答案是不一定
。
生成器都是 Iterator 對象,但 list、dict、str 雖然是 Iterable,卻不是 Iterator。
那如果想要把 list、dict、str等 Iterable 變成 Iterator的話,可以使用 iter()
函數:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from collections import Iterator print("iter( [] ) list 列表是否為叠代器:", isinstance( iter([]), Iterator) ) print("iter( () ) tuple 元組是否為叠代器:", isinstance( iter(()), Iterator) ) print("iter( {} ) dict 字典是否為叠代器:", isinstance( iter({}), Iterator ) ) print("iter( ( x for i in range(10) ) ) generator 生成器是否為叠代器:", isinstance( iter(( x for i in range(10) ) ), Iterator ) ) print("iter( 123 ) 數字是否為叠代器:", isinstance(iter(123), Iterator)) ---------------執行結果--------------- iter( [] ) list 列表是否為叠代器: True iter( () ) tuple 元組是否為叠代器: True iter( {} ) dict 字典是否為叠代器: True iter( ( x for i in range(10) ) ) generator 生成器是否為叠代器: True Traceback (most recent call last): File "/Python/project/interator_pratice.py", line 16, in <module> print("iter( 123 ) 數字是否為叠代器:", isinstance(iter(123), Iterator)) TypeError: ‘int‘ object is not iterable Process finished with exit code 1
創建立一個普通的列表叫 a = [ 1, 2, 3, ]
, 然後使用 iter(a)
函數,這時候它就是一個叠代器了,然後在賦值給 b = iter(a)
,再來去用 __next__()
方法去調用它。
>>> from collections import Iterator
>>> a = [ 1, 2, 3 ]
>>> iter(a)
<list_iterator object at 0x10f91ee80>
>>> b = iter(a)
>>> b.__next__()
1
>>> b.__next__()
2
>>> b.__next__()
3
>>> b.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
你可能會問,為什麼 list、dict、str 等數據類型不是 Iterator ?
這是因為 Python 的 Iterator 對象表示的是一個數據流, Iterator 對象可以被 __next__()
函數調用,並不斷返回下一個數據,直到沒有數據時,拋出 StopIteration的錯誤
;可以把這個數據流看成是一個 有序序列
,但我們卻不能提前知道序列的長度,只能不斷地透過 __next__()
函數實現按需計算下一個數據,所以Iterator的計算是 惰性的
,只有在需要返回下一個數據時,它才會計算。
Iterator甚至可以表示一個無限大的數據流,例如:全體自然數。而使用 list 是永遠不可能存儲全體自然數的。
小結
凡是可以作用於for循環的對象都是 Iterable 類型
凡是可作用於 __next__() 函數的對象,都是 Iterator 類型,它們表示一個惰性計算的序列
集合數據類型,如: list 、 dict 、 str 等是 Iterable ,但不是 Iterator ,不過可以通過 iter() 函數獲得一個 Iterator 對象。
Python 的 for 循環本質上就是通過不斷調用 next() 函數實現的,例如:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
for i in [1, 2, 3, 4, 5]:
print(i)
實際上完全等於下面的代碼
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# 先獲得 Iterator 對象
it = iter([1, 2, 3, 4, 5])
# 循環
while True:
try:
# 獲取下一個值
x = next(it)
# 把取到的值給打印出來
print(x)
# 遇到 StopIteration 就退出循環
except StopIteration:
break
透過上面代碼的解說,可以明白清楚地了解到 Python 3.x 的 range() 函數,其實本身就是叠代器,只是被封裝了起來。
Python 3.6.0 (default, Dec 24 2016, 00:01:50)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> range(0, 10)
range(0, 10)
>>>
但在 Python 2.7 的 range() 函數,就只是一個列表
Python 2.7.13 (default, Apr 4 2017, 08:46:44)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
那在 Python 2.7 中,想要把 range() 函數變成一個叠代器,只要使用 xrange() 函數,就可以把它變成一個叠代器了
Python 2.7.13 (default, Apr 4 2017, 08:46:44)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> xrange(0, 10)
xrange(10)
>>>
它真是一個叠代器嗎?來…讓我們來驗証
Python 2.7.13 (default, Apr 4 2017, 08:46:44)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> dir(xrange(0, 10))
[‘__class__‘, ‘__delattr__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__len__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__reversed__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘]
>>> i = xrange(0, 10)
>>> a = iter(i)
>>> dir(a)
[‘__class__‘, ‘__delattr__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__length_hint__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘next‘]
>>> a.next()
0
...(略)
>>> a.next()
9
>>> a.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
好,現在大夥都知道什麼是 可叠代對象
跟 叠代器
,那接下來考考大家一個問題
a = [ 1, 2, 3 ]
- Q1: 上面代碼是
可叠代對象
嗎?
Ans: 是。詳解如下
>>> from collections import Iterable
>>> a = [ 1, 2, 3 ]
>>> print("a 是否為可叠代對象:", isinstance(a, Iterable) )
a 是否為可叠代對象: True
- Q2: 上面代碼是
叠代器
嗎?
Ans: 不是。因為 a
沒有 __next__
方法,所以不叫叠代器,我們透過 dir()
就可以查出 a 所有可以使用的方法有哪些,詳情如下。
>>> dir(a)
[‘__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‘]
>>>
Python 函數與常用模組 - 叠代器