Python(二) Python中的迭代器和生成器

迭代器

迭代时访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个远胜于开始访问,直到所有元素被访问完结束。迭代器只能往前不会后退。
迭代器的优点是占用极小的内存空间。

可迭代对象

列表、元组、字符串等类型的数据可以使用for…in…的循环来依次拿到数据进行使用,这个过程称为遍历,也叫迭代。
一个类中只要有__iter__方法,那么它就是一个可迭代对象;一个类中既有__iter_方法, 又有__next__方法,那么它就是一个迭代器。因此如果一个对象是一个迭代器,那么它一定可迭代;但是一个对象可迭代,它不一定是一个迭代器。

利用类的内置方法自己实现一个迭代器

若for temp in xxx_obj,那么该语句实现的实际流程为:

  1. 判断当前对象xxx_obj是否为可迭代的对象:看类对象中是否创建了方法__iter__。
  2. 在第1步成立的前提下,调用方法__iter__得到xxx_obj对象的__iter__方法返回值。
  3. __iter__方法的返回值是一个迭代器,而后调用__next__方法进行循环遍历。

下面给出自己实现的一个迭代器的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from collections import Iterable
from collections import Iterator
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
"""如果想要一个对象称为一个 可以迭代的对象,即可以使用for,那么必须实现__iter__方法"""
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
def main():
classmate = Classmate()
classmate.add("张灿")
classmate.add("里斯")
classmate.add("王五")
# print("判断classmate是否是可以迭代的对象:", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("判断classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator))
for name in classmate:
print(name)
if __name__ == "__main__":
main()

迭代器的应用

斐波那契数列迭代器的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Fibonacci(object):
def __init__(self, all_num):
self.all_num = all_num
self.current_num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.all_num:
ret = self.a
self.a, self.b = self.b, self.a + self.b
self.current_num += 1
return ret
else:
raise StopIteration
fibo = Fibonacci(100)
for num in fibo:
print(num)

生成器

生成器是一个特殊的迭代器。生成器表达式并不真正的创建列表,而不是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目“产生”(yield)出来。当一个序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析,以避免占用过多的资源。

创建生成器方法1

生成器创建的语法:

1
2
(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)

创建生成器方法2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
yield a # 如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器模板
a, b = b, a+b
current_num += 1


# 如果在调用create_num的时候,发现这个函数中有yield,那么此时不是调用函数,而是创建一个生成器对象
obj = create_num(10)

for num in obj:
print(num)