range是迭代器吗
一直以为range是迭代器,所以很自然地用next方法试图迭代它的时候,居然报了下面的错误:1
2
3
4
5
6
7
8#range不是迭代器的事实
x = range(3)
print(next(x))
-------------------
Traceback (most recent call last):
File "pythonscripts/iterator_and_range.py", line 8, in <module>
print(next(x))
TypeError: 'range' object is not an iterator
那么这就有意思了,既然range不是迭代器,那么它究竟是什么?
迭代器的特性
我们先来复习一下迭代器的定义, 迭代器是指实现了迭代协议的对象,迭代协议是指实现了iter方法并返回一个实现了next方法的迭代器对象,并通过StopIterator异常标识迭代完成。
使用iter函数可以从任何可迭代对象中获取一个迭代器
1 | s = iter([1,2,3]) |
迭代器有个特点,即每用完一个元素即消耗掉该元素,不会保留在迭代器中,也就是说,是一次性的。
迭代器上使用iter会得到相同的对象
1 | s = iter([1,2,3]) |
利用这个特性,我们可以实现一些特殊的操作:1
2
3
4s = iter([1,2,3,4])
list(zip(s,s))
------------------
[(1, 2), (3, 4)]
range有上述的特性吗
1 | s = iter(range(5)) |
从这里可以看出iter可以用在range上,并返回了一个迭代器。
1 | x = range(5) |
这里可以看出,range并不是一次性的,而是可以重复地使用,不符合迭代器一次性的特性
而且,迭代器(生成器)并不支持长度,而range支持len方法:1
2
3
4
5
6
7x = iter([1,2,3])
print(len(x))
-------------
Traceback (most recent call last):
File "pythonscripts/iterator_and_range.py", line 11, in <module>
print(len(x))
TypeError: object of type 'list_iterator' has no len()
也不可以被索引:1
2
3
4
5
6
7x = iter([1,2,3])
print(x[0])
------------
Traceback (most recent call last):
File "pythonscripts/iterator_and_range.py", line 11, in <module>
print(x[0])
TypeError: 'list_iterator' object is not subscriptable
综上,range并不是迭代器,而且跟迭代器有着明显的区别,只是range是一种可迭代的对象,表面上看起来像迭代器而已。
那么,range究竟是什么
range实现是c语言写的,源码可以在安装路径下找到,这里我们看一下help方法给我们的结果:
1 | Help on class range in module builtins: |
可以看出range的迭代是通过iter协议实现的,像len等对应的方法也是通过len等方式实现的,也就是说range其实是一种类似迭代器的鸭子类型,而并非真正的迭代器!