我们之前一直在用可迭代对象进行迭代操作,那么到底什么是可迭代对象?
首先我们先回顾一下目前我们所熟知的可迭代对象有哪些:str
、list
、tuple
、dict
、set
。
那为什么我们可以称他们为可迭代对象呢?因为他们都遵循了可迭代协议。
什么是可迭代协议?首先我们先看一段代码:
# 正确
for i in '123':
print(i)
'''
1
2
3
'''
# 错误
for i in 123:
print(i)
'''
Traceback (most recent call last):
File ..., line 6, in <module>
for i in 123:
TypeError: 'int' object is not iterable
'''
注意看报错信息中有这样一句句话:'int' object is not iterable .
。
翻译过来就是整数类型对象是不可迭代的,iterable
表⽰可迭代的,即遵循可迭代协议。
那么如何进行验证指定数据类型是否符合可迭代协议?我们可以通过 dir
函数来查看类中定义好的所有方法。
在打印结果中寻找 __iter__
,如果能找到,那么这个类的对象就是一个可迭代对象。
print('__iter__' in dir(str))
'''
True
'''
我们发现在字符串中可以找到 __iter__
,继续看一下 list
、tuple
、dict
、set
以及文件对象:
print('__iter__' in dir(tuple))
print('__iter__' in dir(list))
print('__iter__' in dir(open("1.txt", 'w')))
print('__iter__' in dir(set))
print('__iter__' in dir(dict))
'''
True
True
True
True
True
'''
我们发现这几个可以进行 for 循环的对象都有 __iter__
函数, 包括 range
也有:
print('__iter__' in dir(range(1, 2, 3)))
'''
True
'''
有两个和可迭代对象相关的两个类型分别是:
Iterable
:可迭代的类型;Iterator
:迭代器类型;
所以我们还可以通过 isinstence()
函数来查看一个对象是否是这两个类型的实例:
from collections import Iterable
from collections import Iterator
lst = [1, 2, 3]
lst_iter = lst.__iter__()
print(isinstance(lst, Iterable), isinstance(lst, Iterator))
print(isinstance(lst_iter, Iterable), isinstance(lst_iter, Iterator))
'''
True False
True True
'''
综上,我们可以确定,如果对象中有 __iter__
函数,那么我们认为这个对象遵守了可迭代协议,就可以获取到相应的迭代器。这里的 __iter__
是帮助我们获取到对象的迭代器,我们可以使用迭代器中的 __next__()
来逐个获取迭代器中的元素。
说到这里,那么 for 循环的原理到底是什么?继续看代码:
str = 'hello'
str_iter = str.__iter__()
print(str_iter.__next__())
print(str_iter.__next__())
print(str_iter.__next__())
print(str_iter.__next__())
print(str_iter.__next__())
print(str_iter.__next__()) # 这行报错
'''
h
e
l
l
o
Traceback (most recent call last):
File ..., line 8, in <module>
print(str_iter.__next__())
StopIteration
'''
可以揭晓了,for 循环的机制其实如下:
str = 'hello'
str_iter = str.__iter__()
while True:
try:
item = str_iter.__next__()
print(item)
except StopIteration:
break
'''
h
e
l
l
o
'''
小结
可迭代对象与迭代器:
Iterable
:可迭代对象,内部包含__iter__()
函数;Iterator
:迭代器,内部包含__iter__()
同时包含__next__()
;
迭代器的特点:
- 节省内存;
- 惰性机制;
- 不能反复, 只能向下执行;
评论区