1.定义
可迭代对象(Iterable类型):可迭代对象是指任何定义了__iter__方法的对象。可迭代对象的__iter__方法负责返回一个迭代器。
迭代器(Iterator类型):Python中的迭代器是包含__next__方法(即,能够响应next函数)的任何对象。Iterator对象表示一个惰性计算序列。只能不断通过next()函数实现按需计算下一个数据,直到遇到StopIteration错误。
生成器(Geneator类型):生成器是一种迭代器。与普通函数不同,生成器只会在响应迭代操作时才会运行。
生成器可以是迭代器,但不一定是迭代对象;并非所有的迭代器都是迭代对象。
Python中for循环用于对序列(例如字符串、元组或列表)或其他可迭代对象中的元素进行迭代。所有能用于for循环的对象都是Iterable类型。for循环的本质就是不断调用next()函数。Python中for循环的用法类似于Java中的foreach。
for i in [1,2,3,4]:
pass
print(i)
在Python语言中,for循环中定义的变量i在退出for循环时的值等于可迭代对象的最后一个值。for循环的具体执行过程如下:
- [1,2,3,4]通过iter()转化成迭代器。
- 然后对该迭代器调用next()函数,不断输出迭代器中的内容,并复制给i
- 连续执行4次next()之后,i等于4,继续执行next()函数,抛出StopIteration异常。for循环结束。
2.双层for循环中使用迭代器和生成器
从上面的代码中可以看出enumerate()产生的生成器在双层for循环中并没有达到我们要的效果。
3.自定义可迭代对象及迭代器
3.1 自定义可迭代对象(在类定义中实现__iter__函数)
这种写法实际上是一种委托迭代的写法,这里的迭代方式借助了其他迭代对象。
class Node(object):
def __init__(self):
self._children=[]
def add_child(self,value):
self._children.append(value)
def __iter__(self):
return iter(self._children)
if __name__=="__main__":
node_1=Node()
node_1.add_child(5)
node_1.add_child(4)
for node in node_1:
print(node)
3.2 用生成器创建新的迭代方式
python中的range()只能接受整数,如果想要一个能够接受浮点型的类range()的话,可以使用yield构造一个生成器。
def frange(start,stop,increment):
x=start
while x<stop:
yield x
x+=increment
a=frange(1,5,0.5)
for i in a:
print(i,end=' ')
4.其他
4.1 反向迭代
反向迭代的实现主要内建函数reversed()和__reversed__()函数。以实现倒计时类为例:
class CountDown(object):
def __init__(self,start):
self.start=start
def __reversed__(self):
n=self.start
while n>0:
yield n
n-=1
countDown=CountDown(10)
for item in reversed(countDown):
print(item)
- 如果在CountDown类中只实现了__reversed__()方法,而没有实现__iter__()方法的话,countDown(CountDown的实例)不能使用for in中。因为countDown不是可迭代对象,不是迭代器,更不是生成器。
- 由于在CountDown类中实现了__reversed__()方法,所以countDown可以响应reversed()函数。并且reversed(countDown) 可以使用for in 语法。
4.2 对迭代器做切片操作
list对象可以在中括号[]执行普通的切片操作,但是对其他迭代器则是无法直接使用切片操作。主要有以下两个方面的原因:
- 首先,通常我们无法准确地知道迭代器和生成器的准确长度
- 其次,一般迭代器和生成器都没有实现索引。
如果想对迭代器和生成器使用类似切片操作,可以使用itertools.islice()函数。islice()函数可以产生一个迭代器,并产生所需要的切片元素。
import itertools
def count(n):
while True:
yield n
n+=1
c=count(10)
for i in itertools.islice(c,1,5):
print(i)
print("==========")
for i in itertools.islice(c,2,5):
print(i)
b=list(range(50))
print("===========")
for i in itertools.islice(b,1,5):
print(i)
print("============")
for i in itertools.islice(b,2,5):
print(i)
代码运行结果如下:
从以下代码运行结果可以看出,islice()会消耗掉所提供的迭代器中的数据。但是对于list列表中的数据,并没有被消耗。
11 12 13 14 ========== 17 18 19 ========== 1 2 3 4 ========== 2 3 4 |