06-06 迭代器

一. 迭代器介绍

"""
# 什么是迭代器?
	迭代器指的是用来迭代取值的工具, 迭代就是一个重复的过程, 每次重复都是基于上一次的结果而继续的. 单纯的重复并不是迭代.

# 为什么要用迭代器?
	迭代器是用来迭代取值的工具, 而涉及到把多个值循环取出来的类型有:
列表, 字符串, 元组, 字典, 集合, 打开的文件

    li = ['egon', 'liu', 'alex']
    i = 0
    while i < len(li):
        print(li[i])
        i += 1
	上述迭代取值的方式只适用于有索引的数据类型: 列表, 字符串, 元组
	
	为什么要用迭代器真正原因: 为了摆脱索引取值的局限性, python提供了一种能够不依赖索引取的方式, 这就是迭代器.
	
# 区分迭代与单纯的重复:	
	一次对过程的重复称之为一次"迭代", 而每一次迭代得到的结果会作为下一次迭代的初始值.
"""
# 单纯的重复
while True:
    msg = input(">>:").strip()
    print(msg)
    
# 需求: 使用while循环打印列表中的每项元素的值
# while循环是一个重复的过程, 且每次重复都是基于上一次的index累加操作之后的结果而继续的, 所以这是一个迭代现象.
goods = ['mac', 'lenovo', 'acer', 'dell', 'sony']
index = 0
while index < len(goods):
    print(goods[index], end=' ')   # mac lenovo acer dell sony 
    index += 1

1.可迭代对象

"""
什么是可迭代对象? 可迭代对象: iterable
	从语法层面上讲, 内置有__iter__()方法的的对象, 内置可以iter()的对象.
	举例: 字符串, 列表, 元组, 字典, 集合, 打开的文件
"""
s1 = ''
print(s1.__iter__())
print(iter(s1))  # <str_iterator object at 0x000001B0074DBBE0>

li = []
print(li.__iter__())
print(iter(li))  # <list_iterator object at 0x000001B0074DBBE0>

t = (1,)
print(t.__iter__())
print(iter(t))  # <tuple_iterator object at 0x000001B0074DBBE0>

d = {'a': 1}
print(d.__iter__())
print(iter(d))  # <dict_keyiterator object at 0x000001B00755B770>

set1 = {1, 2, 3}
print(set1.__iter__())
print(iter(set1))  # <dict_keyiterator object at 0x000001B00755B770>

with open('a.txt', mode='w') as f:
    print(f.__iter__())
    print(iter(f))  # <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>

2.迭代器对象

"""
# 什么是迭代器对象? 迭代器: iterator
	从语法层面上讲, 内置有__iter__()和__next__()方法的的对象, 内置可以iter()和next()的对象.
	
# 如何得到迭代器对象:	
	可迭代对象执行__iter__()和iter()得到了迭代器对象.
	
# 迭代器对象执行__iter__()和iter()仍然是迭代器本身
	迭代器执行__iter__()方法和iter()就是迭代器本身, 为什么迭代器对象下也要有内置__iter__()方法和iter()?
		主要为了满足for循环迭代取值. for循环上来的第一件事就是调用你需要遍历的对象下的__iter__()方法, 无论你需要遍历的对象是可迭代对象, 还是迭代器对象. 减少这种区分的可能性.

	
总结: 
	1. 调用可迭代对象下的__iter__()方法或者iter()会将其转换成迭代器对象
	2. 转换成迭代器对象以后, 就可以使用内置方法__next__()或者next()迭代取值, 且每迭代取值一次, 都会作为下一次迭代取值的初始值.(字典默认迭代的是key)
	3. 当迭代器对象迭代完毕以后, 继续迭代会抛出异常: StopIteration
	4. 当抛出异常时, 也就是迭代器对象被迭代取值完毕时, 我们可以使用异常处理机制捕捉异常
	5. 在迭一个迭代器迭代取值干净的情况下, 再对其取值取不到. 如果需要再次取值, 需要对可迭代对象重新使用__iter__()或者iter()生成一个新的迭代器对象.
"""
# 示例一: 调用可迭代对象下的__iter__()方法或者iter()会将其转换成迭代器对象
dic = {'a': 1, 'b': 2, 'c': 3}
dic_iterator = dic.__iter__()

# 示例二: 转换成迭代器对象以后, 就可以使用内置方法__next__()或者next()迭代取值, 且每迭代取值一次, 都会作为下一次迭代取值的初始值.(字典默认迭代的是key)
print(dic_iterator.__next__())  # a
print(dic_iterator.__next__())  # b
print(dic_iterator.__next__())  # c

# 示例三: 当迭代器对象迭代完毕以后, 继续迭代会抛出异常: StopIteration
print(dic_iterator.__next__())  # 抛出异常: StopIteration

# 示例四: 当抛出异常时, 也就是迭代器对象被迭代取值完毕时, 我们可以使用异常处理机制捕捉异常
'''
# 伪代码示例: 
try: 
	会出现异常的代码
except 捕捉的抛出异常的类型:
	捕捉异常以后要继续进行的操作
'''
dic_iterator = dic.__iter__()
while True:
    try:
        print(dic_iterator.__next__())
    except StopIteration:
        break

# 示例五: 基于示例四, 在迭一个迭代器迭代取值干净的情况下, 再对其取值取不到. 如果需要再次取值, 需要对可迭代对象重新使用__iter__()或者iter()生成一个新的迭代器对象.
print('=======>')  # =======>
dic_iterator = dic.__iter__()
while True:
    try:
        print(dic_iterator.__next__())
    except StopIteration:
        break

3.可迭代对象与迭代器对象之间的关系

"""
# 可迭代对象:
	1. 从语法层面上讲, 内置有__iter__()方法和可以使用iter()的对象
	2. 可迭代对象可以通过__iter__()方法或者可以使用iter()得到迭代器对象
	示例: 
		可迭代对象.__iter__() --> 生成迭代器对象
		iter(可迭代对象) ---> 生成迭代器对象

# 迭代器对象:
	1. 从语法层面上讲, 内置有__next__()方法和可以使用next(), 也能使用__iter__()方法和可以使用iter()的对象
	2. 迭代器对象执行__next__()方法或者使用next()得到迭代器的下一个值
	示例:
		迭代器对象.__next__() --> 迭代器的下一个值
		next(迭代器对象) --> 迭代器的下一个值
		
	3. 迭代器对象执行__iter__()方法或者使用iter()得到迭代器本身.(调用了和没调用一模一样)
	示例:
		迭代器对象.__iter__() --> 得到迭代器本身
		iter(迭代器对象) --> 得到迭代器本身
"""
# 验证: 迭代器对象执行__iter__()方法或者使用iter()得到迭代器本身.(调用了和没调用一模一样)
dic = {'a': 1, 'b': 2, 'c': 3}
dic_iterator = iter(dic)

print(dic_iterator is iter(dic_iterator).__iter__().__iter__())  # True

二. for循环原理

'''
for循环与while循环:
	while循环称之为条件循环, 条件为False, 循环结束.
	for循环也可以称之为迭代循环, 遍历对象迭代取值完毕, 循环结束.

for循环底层原理: 迭代取值做的三件事
	1.把准备要遍历的对象, 无论是什么类型, 上来直接使用内置的__iter__()方法得到一个迭代器对象.
	2.然后通过拿到的迭代器对象, 直接使用内置的__next__()迭代取值, 把取到的值赋值给in前面自定义的变量名.
	3.循环往复步骤2, 直到迭代取值完毕抛出异常StopIteration, 接着for循环会捕捉异常, 最后结束循环.
'''
# 示例: 使用for循环遍历取值
goods = ['mac', 'lenovo', 'acer', 'dell', 'sony']
for item in goods:
    print(item, end=' ')  # mac lenovo acer dell sony 
    
# 示例: 调用list()功能, 与for循环原理相同    
list('hello')

# 使用while循环 + try...except实现迭代取值. 迭代器迭代完毕except捕获异常: StopIteration
goods = ['mac', 'lenovo', 'acer', 'dell', 'sony']
iterator_goods = iter(goods)
while True:
    try:
        print(next(iterator_goods), end=' ')  # mac lenovo acer dell sony
    except StopIteration:
        break

三. 总结: 迭代器的优缺点

"""
优点:
	1. 为序列和非序列类型提供了统一的迭代取值方式
	2. 惰性计算: 对迭代器本身来说, 同一时刻在内存中只有一个值, 它可以存放无限大的数据流.
	
缺点:
	1. 除非取尽, 否则无法获取迭代器的长度
	2. 不能控制取值顺序, 只能取下一个值, 更不能回到开始. 若想重新获取值, 只能重新调用__iter__()方法和iter()生成一个新的迭代器. 
"""
posted @ 2020-03-24 20:48  给你加马桶唱疏通  阅读(164)  评论(0编辑  收藏  举报