概念
- 使用for循环对列表、元组、字符串等类型挨个提取数据,该过程称之为遍历,也叫迭代
- 迭代器是一个包含数值的对象
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问结束,迭代器只前不后
- 迭代器可以记住遍历对象的位置,当调用
next()
方法时就会返回下一个值,做到随用随取,不会占用很多内存空间。
- 一个对象如果有
__iter__()
方法并且该方法返回值有__next__()
方法,那么该对象就为迭代器
- 一个可迭代对象调用了
__iter__()
方法才返回迭代器
可迭代对象
for语句之所以能够遍历,是因为有迭代器的支持。for语句在遍历时调用遍历对象的__iter__()
方法,如果遍历对象没有该方法就不能对其进行迭代,也就是不能遍历该对象
1 2 3 4 5 6 7
|
a = 123 print(a.__iter__())
AttributeError: 'int' object has no attribute '__iter__'
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
a = "123" print(a.__iter__())
for i in a: print(i)
<str_iterator object at 0x000002C2A413C8C8> 1 2 3
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from collections.abc import Iterable
num = 123 txt = "123" lis = [1,2,3]
print(isinstance(num, Iterable)) print(isinstance(txt, Iterable)) print(isinstance(lis, Iterable))
False True True
|
迭代器
如果对象有__iter__()
方法时,for语句就会把__iter__()
方法的返回值当成一个对象,并且调用这个对象的__next__()
方法。如果可迭代对象有__iter__()
方法并且该方法返回值有__next__()
方法,那么该对象就为迭代器
可迭代对象调用完__iter__()
方法后才返回迭代器,可迭代对象不调用__iter__()
方法就不是迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from collections.abc import Iterator
num = 123 txt = "123" lis = [1,2,3]
print(isinstance(num, Iterator)) print(isinstance(txt, Iterator)) print(isinstance(lis, Iterator))
False False False
|
使用iter()
方法可以获得可迭代对象的迭代器,下述代码返回True
表示使用iter()
方法后返回的对象为迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from collections.abc import Iterator
txt = iter("123") lis = iter([1,2,3])
print(txt) print(lis) print(isinstance(txt, Iterator)) print(isinstance(lis, Iterator))
<str_iterator object at 0x000002E94EAA8F08> <list_iterator object at 0x000002E94EAEC748> True True
|
如果为迭代器则可以使用__next__()
方法或next()
方法来查看每一次的返回值,如果可迭代对象被遍历完之后再进行迭代则会抛出异常 。for循环就相当于创建的迭代对象的迭代器,并循环执行每个迭代器的__next__()
方法
1 2 3 4 5 6 7 8 9 10 11 12
| lis = iter([1,2,3])
print(lis.__next__()) print(next(lis))
1 2
|
创建迭代器
创建一个类来作为迭代器,在类中定义__iter__()
方法并返回迭代器,在类中定义__next__()
方法并对传递进来的数据进行处理。为了防止迭代一直进行,可以在__next__()
方法中使用raise StopIteration
抛出异常终止迭代
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 31 32 33
|
class MyIterator(object): """迭代器,对传递进来的数据反向输出""" def __init__(self, data): self.data = data self.index = len(data)
def __iter__(self): return self
def __next__(self): if self.index == 0: raise StopIteration
self.index -= 1 return self.data[self.index]
lis = [1,2,3,4,5] my_iterator = MyIterator(lis) print(next(my_iterator)) print(next(my_iterator)) print(next(my_iterator)) print(next(my_iterator)) print(next(my_iterator))
5 4 3 2 1
|
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 31 32 33 34 35 36 37
|
class MyNumber(object): """迭代对象""" def __init__(self, data): self.data = data
def __iter__(self): return MyIterator(self.data)
class MyIterator(object): """迭代器,对传递进来的数据反向输出""" def __init__(self, data): self.data = data self.index = len(data)
def __next__(self): if self.index == 0: raise StopIteration
self.index -= 1 return self.data[self.index]
lis = [1,2,3,4,5] my_number = MyNumber(lis)
for i in my_number: print(i)
5 4 3 2 1
|
应用场景
场景
- 数列的数据过于庞大时
- 数列有规律,但不能通过列表推导式表
斐波那契数列
介绍
数列中的第1个元素为0,第二个元素为1,第n个元素为前两个之和,如0 1 1 2 3 5 8 13
不使用迭代器
不使用迭代器时直接将运算结果写到列表中,再进行遍历。如果需要运算的斐波那契范围庞大,则需要等待运算完成后才能进行遍历(浪费时间),遍历前要把庞大的运算结果写入列表(浪费内存)
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
| num_list = [] a = 0 b = 1 count = 0
while count < 10: num_list.append(a) a, b = b, a + b count += 1
for i in num_list: print(i)
0 1 1 2 3 5 8 13 21 34
|
使用迭代器
迭代器不会一次性将所有的元素都加载到内存中,而是需要使用的使用才返回结果
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 31 32 33 34 35 36 37 38
| class Fibonacci(object): """斐波那契数列的迭代器""" def __init__(self, all_num): self.a = 0 self.b = 1 self.all_num = all_num self.current_num = 0
def __iter__(self): return self
def __next__(self): if self.current_num < self.all_num: result = self.a self.a, self.b = self.b, self.a + self.b self.current_num += 1 return result
else: raise StopIteration
fibonacci = Fibonacci(10)
for i in fibonacci: print(i)
0 1 1 2 3 5 8 13 21 34
|
内存对比 (不要在物理测试,系统直接卡死)
不使用迭代器运算100000000次时,系统被迫停止该进程,内存占用狂飙(总占用因卡顿未及时刷新)
使用迭代器运算100000000次时,内存占比稳定在0.6左右,并且运行正常
g)