Skip to content

Commit cb3f3e2

Browse files
committed
add iterator
1 parent c924519 commit cb3f3e2

1 file changed

Lines changed: 212 additions & 0 deletions

File tree

Advanced-Features/iterator.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,214 @@
1+
迭代器 (Iterator)
2+
====
3+
4+
# 迭代和可迭代
5+
6+
迭代器这个概念在很多语言中(比如 C++,Java)都是存在的,但是不同语言实现迭代器的方式各不相同。**在 Python 中,迭代器是指遵循迭代器协议(iterator protocol)的对象。**至于什么是迭代器协议,稍后自然会说明。为了更好地理解迭代器,我先介绍和迭代器相关的两个概念:
7+
8+
- 迭代(Iteration)
9+
- 可迭代对象(Iterable)
10+
11+
你可能会觉得这是在玩文字游戏,但这确实是要搞清楚的。
12+
13+
> 当我们用一个循环(比如 for 循环)来遍历容器(比如列表,元组)中的元素时,这种遍历的过程就叫***迭代***
14+
15+
在 Python 中,我们使用 `for...in...` 进行迭代。比如,遍历一个 list:
16+
17+
```python
18+
numbers = [1, 2, 3, 4]
19+
for num in numbers:
20+
print num
21+
```
22+
23+
像上面这种可以使用 `for` 循环进行迭代的对象,就是可迭代对象,它的定义如下:
24+
25+
> 含有 `__iter__()` 方法或 `__getitem__()` 方法的对象称之为***可迭代对象***
26+
27+
我们可以使用 Python 内置的 `hasattr()` 函数来判断一个对象是不是可迭代的:
28+
29+
```python
30+
>>> hasattr((), '__iter__')
31+
True
32+
>>> hasattr([], '__iter__')
33+
True
34+
>>> hasattr({}, '__iter__')
35+
True
36+
>>> hasattr(123, '__iter__')
37+
False
38+
>>> hasattr('abc', '__iter__')
39+
False
40+
>>> hasattr('abc', '__getitem__')
41+
True
42+
```
43+
44+
另外,我们也可使用 `isinstance()` 进行判断:
45+
46+
```python
47+
>>> from collections import Iterable
48+
49+
>>> isinstance((), Iterable) # 元组
50+
True
51+
>>> isinstance([], Iterable) # 列表
52+
True
53+
>>> isinstance({}, Iterable) # 字典
54+
True
55+
>>> isinstance('abc', Iterable) # 字符串
56+
True
57+
>>> isinstance(100, Iterable) # 数字
58+
False
59+
```
60+
61+
可见,我们熟知的字典(dict)、元组(tuple)、集合(set)和字符串对象都是可迭代的。
62+
163
# 迭代器
264

65+
现在,让我们看看什么是迭代器(Iterator)。上文说过,**迭代器是指遵循迭代器协议(iterator protocol)的对象。**从这句话我们可以知道,迭代器是一个对象,但比较特别,它需要遵循迭代器协议,那什么是迭代器协议呢?
66+
67+
> ***迭代器协议(iterator protocol)***是指要实现对象的 `__iter()__``next()` 方法(注意:Python3 要实现 `__next__()` 方法),其中,`__iter()__` 方法返回迭代器对象本身,`next()` 方法返回容器的下一个元素,在没有后续元素时抛出 `StopIteration` 异常。
68+
69+
接下来讲讲迭代器的例子,有什么常见的迭代器呢?列表是迭代器吗?字典是迭代器吗?我们使用 `hasattr()` 进行判断:
70+
71+
```
72+
>>> hasattr((1, 2, 3), '__iter__')
73+
True
74+
>>> hasattr((1, 2, 3), 'next') # 有 __iter__ 方法但是没有 next 方法,不是迭代器
75+
False
76+
>>>
77+
>>> hasattr([1, 2, 3], '__iter__')
78+
True
79+
>>> hasattr([1, 2, 3], 'next')
80+
False
81+
>>>
82+
>>> hasattr({'a': 1, 'b': 2}, '__iter__')
83+
True
84+
>>> hasattr({'a': 1, 'b': 2}, 'next')
85+
False
86+
```
87+
88+
同样,我们也可以使用 `isinstance()` 进行判断:
89+
90+
```
91+
>>> from collections import Iterator
92+
>>>
93+
>>> isinstance((), Iterator)
94+
False
95+
>>> isinstance([], Iterator)
96+
False
97+
>>> isinstance({}, Iterator)
98+
False
99+
>>> isinstance('', Iterator)
100+
False
101+
>>> isinstance(123, Iterator)
102+
False
103+
```
104+
105+
可见,**虽然元组、列表和字典等对象是可迭代的,但它们却不是迭代器!**对于这些可迭代对象,可以使用 Python 内置的 `iter()` 函数获得它们的迭代器对象,看下面的使用:
106+
107+
```
108+
>>> from collections import Iterator
109+
>>> isinstance(iter([1, 2, 3]), Iterator) # 使用 iter() 函数,获得迭代器对象
110+
True
111+
>>> isinstance(iter('abc'), Iterator)
112+
True
113+
>>>
114+
>>> my_str = 'abc'
115+
>>> next(my_str) # my_str 不是迭代器,不能使用 next(),因此出错
116+
---------------------------------------------------------------------------
117+
TypeError Traceback (most recent call last)
118+
<ipython-input-15-5f369cd8082f> in <module>()
119+
----> 1 next(my_str)
120+
121+
TypeError: str object is not an iterator
122+
>>>
123+
>>> my_iter = iter(my_str) # 获得迭代器对象
124+
>>> isinstance(my_iter, Iterator)
125+
True
126+
>>> next(my_iter) # 可使用内置的 next() 函数获得下一个元素
127+
'a'
128+
```
129+
130+
事实上,Python 的 `for` 循环就是先通过内置函数 `iter()` 获得一个迭代器,然后再不断调用 `next()` 函数实现的,比如:
131+
132+
```
133+
for x in [1, 2, 3]:
134+
print i
135+
```
136+
137+
等价于
138+
139+
```python
140+
# 获得 Iterator 对象
141+
it = iter([1, 2, 3])
142+
143+
# 循环
144+
while True:
145+
try:
146+
# 获得下一个值
147+
x = next(it)
148+
print x
149+
except StopIteration:
150+
# 没有后续元素,退出循环
151+
break
152+
```
153+
154+
# 斐波那契数列迭代器
155+
156+
现在,让我们来自定义一个迭代器:斐波那契(Fibonacci)数列迭代器。根据迭代器的定义,我们需要实现 `__iter()__``next()` 方法(在 Python3 中是 `__next__()` 方法)。先看代码:
157+
158+
```python
159+
# -*- coding: utf-8 -*-
160+
161+
from collections import Iterator
162+
163+
class Fib(object):
164+
def __init__(self):
165+
self.a, self.b = 0, 1
166+
167+
# 返回迭代器对象本身
168+
def __iter__(self):
169+
return self
170+
171+
# 返回容器下一个元素
172+
def next(self):
173+
self.a, self.b = self.b, self.a + self.b
174+
return self.a
175+
176+
def main():
177+
fib = Fib() # fib 是一个迭代器
178+
print 'isinstance(fib, Iterator): ', isinstance(fib, Iterator)
179+
180+
for i in fib:
181+
if i > 10:
182+
break
183+
print i
184+
185+
if __name__ == '__main__':
186+
main()
187+
```
188+
189+
在上面的代码中,我们定义了一个 Fib 类,用于生成 Fibonacci 数列。在类的实现中,我们定义了 `__iter__` 方法,它返回对象本身,这个方法会在遍历时被 Python 内置的 `iter()` 函数调用,返回一个迭代器。类中的 `next()` 方法用于返回容器的下一个元素,当使用 `for` 循环进行遍历的时候,就会使用 Python 内置的 `next()` 函数调用对象的 `next` 方法(在 Python3 中是 `__next__` 方法)对迭代器进行遍历。
190+
191+
运行上面的代码,可得到如下结果:
192+
193+
```
194+
isinstance(fib, Iterator): True
195+
1
196+
1
197+
2
198+
3
199+
5
200+
8
201+
```
202+
203+
# 小结
204+
205+
- 元组、列表、字典和字符串对象是可迭代的,但不是迭代器,不过我们可以通过 `iter()` 函数获得一个迭代器对象;
206+
- Python 的 `for` 循环实质上是先通过内置函数 `iter()` 获得一个迭代器,然后再不断调用 `next()` 函数实现的;
207+
- 自定义迭代器需要实现对象的 `__iter()__``next()` 方法(注意:Python3 要实现 `__next__()` 方法),其中,`__iter()__` 方法返回迭代器对象本身,`next()` 方法返回容器的下一个元素,在没有后续元素时抛出 `StopIteration` 异常。
208+
209+
# 参考资料
210+
211+
- [Callback or Iterator in Python](https://code-maven.com/callback-or-iterator-in-python)
212+
- [迭代器 - 廖雪峰的官方网站](http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254193589df9c612d2449618ea460e7a672a366000)
213+
214+

0 commit comments

Comments
 (0)