Skip to content

Commit 9445624

Browse files
committed
iterator
1 parent 767b20b commit 9445624

4 files changed

Lines changed: 195 additions & 0 deletions

File tree

214.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
>For freedom Christ has set us free. Stand firm, therefore, and do not submit again to a yoke of slavery.
2+
3+
>基督释放了我们,叫我们得以自由,所以要站立得稳,不要再被奴仆的轭挟制。(GALATIANS 5:1)
4+
5+
#迭代器
6+
7+
迭代,对于读者已经不陌生了,曾有专门一节来讲述,如果印象不深,请复习[《迭代》](./128.md)
8+
9+
正如读者已知,对序列(列表、元组)、字典和文件都可以用`iter()`方法生成迭代对象,然后用`next()`方法访问。当然,这种访问不是自动的,如果用for循环,就可以自动完成上述访问了。
10+
11+
如果用`dir(list)`,`dir(tuple)`,`dir(file)`,`dir(dict)`来查看不同类型对象的属性,会发现它们都有一个名为`__iter__`的东西。这个应该引起读者的关注,因为它和迭代器(iterator)、内置的函数iter()在名字上是一样的,除了前后的双下划线。望文生义,我们也能猜出它肯定是跟迭代有关的东西。当然,这种猜测也不是没有根据的,其重要根据就是英文单词,如果它们之间没有一点关系,肯定不会将命名搞得一样。
12+
13+
猜对了。`__iter__`就是对象的一个特殊方法,它是迭代规则(iterator potocol)的基础。或者说,对象如果没有它,就不能返回迭代器,就没有`next()`方法,就不能迭代。
14+
15+
>提醒注意,如果读者用的是python3.x,迭代器对象实现的是`__next__()`方法,不是`next()`。并且,在python3.x中有一个内建函数next(),可以实现`next(it)`,访问迭代器,这相当于于python2.x中的`it.next()`(it是迭代对象)。
16+
17+
那些类型是list、tuple、file、dict对象有`__iter__()`方法,标着他们能够迭代。这些类型都是python中固有的,我们能不能自己写一个对象,让它能够迭代呢?
18+
19+
当然呢!要不然python怎么强悍呢。
20+
21+
#!/usr/bin/env python
22+
# coding=utf-8
23+
24+
"""
25+
the interator as range()
26+
"""
27+
class MyRange(object):
28+
def __init__(self, n):
29+
self.i = 0
30+
self.n = n
31+
32+
def __iter__(self):
33+
return self
34+
35+
def next(self):
36+
if self.i < self.n:
37+
i = self.i
38+
self.i += 1
39+
return i
40+
else:
41+
raise StopIteration()
42+
43+
if __name__ == "__main__":
44+
x = MyRange(7)
45+
print "x.next()==>", x.next()
46+
print "x.next()==>", x.next()
47+
print "------for loop--------"
48+
for i in x:
49+
print i
50+
51+
将代码保存,并运行,结果是:
52+
53+
$ python 21401.py
54+
x.next()==> 0
55+
x.next()==> 1
56+
------for loop--------
57+
2
58+
3
59+
4
60+
5
61+
6
62+
63+
以上代码的含义,是自己仿写了拥有`range()`的对象,这个对象是可迭代的。分析如下:
64+
65+
类MyRange的初始化方法`__init__()`就不用赘述了,因为前面已经非常详细分析了这个方法,如果复习,请阅读[《类(2)》](./207md)相关内容。
66+
67+
`__iter__()`是类中的核心,它返回了迭代器本身。一个实现了`__iter__()`方法的对象,即意味着其实可迭代的。
68+
69+
含有`next()`的对象,就是迭代器,并且在这个方法中,在没有元素的时候要发起`StopIteration()`异常。
70+
71+
如果对以上类的调用换一种方式:
72+
73+
if __name__ == "__main__":
74+
x = MyRange(7)
75+
print list(x)
76+
print "x.next()==>", x.next()
77+
78+
运行后会出现如下结果:
79+
80+
$ python 21401.py
81+
[0, 1, 2, 3, 4, 5, 6]
82+
x.next()==>
83+
Traceback (most recent call last):
84+
File "21401.py", line 26, in <module>
85+
print "x.next()==>", x.next()
86+
File "21401.py", line 21, in next
87+
raise StopIteration()
88+
StopIteration
89+
90+
说明什么呢?`print list(x)`将对象返回值都装进了列表中并打印出来,这个正常运行了。此时指针已经移动到了迭代对象的最后一个,正如在[《迭代》](./128.md)中描述的那样,`next()`方法没有检测也不知道是不是要停止了,它还要继续下去,当继续下一个的时候,才发现没有元素了,于是返回了`StopIteration()`
91+
92+
为什么要将用这种可迭代的对象呢?就像上面例子一样,列表不是挺好的吗?
93+
94+
列表的确非常好,在很多时候效率很高,并且能够解决相当普遍的问题。但是,不要忘记一点,在某些时候,列表可能会给你带来灾难。因为在你使用列表的时候,需要将列表内容一次性都读入到内存中,这样就增加了内存的负担。如果列表太大太大,就有内存溢出的危险了。这时候需要的是迭代对象。比如斐波那契数列(在本教程多处已经提到这个著名的数列:[《练习》的练习4](./129.md)[《函数(4)》中递归举例](./204.md)):
95+
96+
#!/usr/bin/env python
97+
# coding=utf-8
98+
"""
99+
compute Fibonacci by iterator
100+
"""
101+
__metaclass__ = type
102+
103+
class Fibs:
104+
def __init__(self, max):
105+
self.max = max
106+
self.a = 0
107+
self.b = 1
108+
109+
def __iter__(self):
110+
return self
111+
112+
def next(self):
113+
fib = self.a
114+
if fib > self.max:
115+
raise StopIteration
116+
self.a, self.b = self.b, self.a + self.b
117+
return fib
118+
119+
if __name__ == "__main__":
120+
fibs = Fibs(5)
121+
print list(fibs)
122+
123+
运行结果是:
124+
125+
$ python 21402.py
126+
[0, 1, 1, 2, 3, 5]
127+
128+
现在给读者一个思考问题:要在斐波那契数列中找出大于1000的最小的数,能不能在上述代码基础上改造得出呢?
129+
130+
迭代器的确有迷人之处,但是它也不是万能之物。比如迭代器不能回退,只能如过河的卒子,不断向前。另外,迭代器也不适合在多线程环境中对可变集合使用(这句话可能理解有困难,先混个脸熟吧,等你遇到多线程问题再说)。
131+
132+
------
133+
134+
[总目录](./index.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[上节:特殊方法(2)](./213.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[下节:生成器](./215.md)
135+
136+
如果你认为有必要打赏我,请通过支付宝:**qiwsir@126.com**,不胜感激。

2code/21401.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
"""
5+
the interator as range()
6+
"""
7+
class MyRange(object):
8+
def __init__(self, n):
9+
self.i = 0
10+
self.n = n
11+
12+
def __iter__(self):
13+
return self
14+
15+
def next(self):
16+
if self.i < self.n:
17+
i = self.i
18+
self.i += 1
19+
return i
20+
else:
21+
raise StopIteration()
22+
23+
if __name__ == "__main__":
24+
x = MyRange(7)
25+
print list(x)
26+
print "x.next()==>", x.next()
27+
print "x.next()==>", x.next()
28+
print "------for loop--------"
29+
for i in x:
30+
print i

2code/21402.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
"""
4+
compute Fibonacci by iterator
5+
"""
6+
__metaclass__ = type
7+
8+
class Fibs:
9+
def __init__(self, max):
10+
self.max = max
11+
self.a = 0
12+
self.b = 1
13+
14+
def __iter__(self):
15+
return self
16+
17+
def next(self):
18+
fib = self.a
19+
if fib > self.max:
20+
raise StopIteration
21+
self.a, self.b = self.b, self.a + self.b
22+
return fib
23+
24+
if __name__ == "__main__":
25+
fibs = Fibs(5)
26+
print list(fibs)
27+
28+

index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
11. [多态和封装](./211.md)==>多态,封装和私有化
5959
12. [特殊方法(1)](./212.md)==>`__dict__``__slots__`
6060
13. [特殊方法(2)](./213.md)==>`__getattr__`,`__setattr__`以及查找属性顺序
61+
14. [迭代器](./214.md)==>迭代器方法`__iter__`,`netx()`
6162

6263
##第三部分:模块
6364

0 commit comments

Comments
 (0)