python的两种循环方式:
(1)for <item> in <iterable>
iterable:可迭代对象
(2)while <expression>
expression:循环成立条件
1. 迭代器
一种迭代其他对象(可迭代对象)的对象。
可迭代对象:字符串、容器类型、生成器类型等,迭代器也是一种可迭代对象
iter(iterable)
返回迭代器对象
(1)对可迭代类型调用,返回迭代器对象。
(2)对不可迭代类型调用,抛出TypeError
异常。
(3)iter(iter(iterable))
即对迭代器对象调用,尝试获取迭代器的迭代器,一定会返回迭代器本身。
next(iter_1)
返回一次迭代器的迭代结果。
(1)当迭代器没有更多的值可以返回时,抛出StopIteration
异常。
for循环原理
for <item> in <iterable>
:
(1)先使用iter(<iterable>)
生成可迭代对象<iterable>
的生成器对象。
(2)不断调用next(iter)
返回迭代结果,直到捕获StopIteration
异常。
2. 自定义迭代器
定义一个迭代器关键在于实现了两个方法:
(1)__iter__
调用iter
方法时触发,迭代器对象调用返回自身。
(2)__next__
调用next
方法时除法,通过return
返回结果,当没有结果可以返回时,抛出异常StopIteration
,在迭代过程中可以多次触发。
3. 可迭代对象
可迭代对象与迭代器的区别:
(1)迭代器是可迭代对象的一种。
(2)可迭代对象调用iter
返回迭代器,而迭代器调用则返回自身。
(3)迭代器迭代过程是一次性的,而可迭代对象不一定。
(4)迭代器需要实现__iter__
与__next__
,可迭代对象则只需要实现__iter__
。一次性的原因:每个迭代器都对应一次完整的迭代过程,在迭代过程中,必须设置变量a来保存当前的状态,即迭代到第几个了。在遍历开始时候,a=start,遍历结束时,a=end;此后除非手动校正,否则a永远等于迭代器结尾,因此无法二次迭代。
class rangeA:
def __init__(self,start,end):
self.start=start
self.end = end
def __iter__(self):#被遍历时返回生成器。
return rangeA_Iterator(self)
class rangeA_Iterator:
def __init__(self,range_obj):
self.range_obj=range_obj
self.current=self.range_obj.start#状态变量
def __next__(self):
"""
next方法,示例中返回当前值而不做其他处理,此处可进行自定义数据处理。
:return:
"""
while self.current<self.range_obj.end:
num=self.current
self.current+=1
return num
raise StopIteration
def __iter__(self):
"""
迭代器iter返回本身
:return:
"""
return self
r=rangeA(0,10)
print(type(r))#<class '__main__.rangeA'>,可迭代对象实例
print(list(r))#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],生成列表时调用iter方法,返回迭代器。
for i in r: #迭代时同样调用iter方法,返回迭代器
print(i)
使用上述方法可以解决迭代器一次性迭代的问题,即通过使定义的可迭代对象与迭代器分离,每次对可迭代对象执行迭代操作时,都会触发
iter
方法而生成一个新的迭代器。
4. 生成器是迭代器
def rangeA_gen(start,end):
num=start
while num<end:
yield num
num+=1
5. 使用可迭代对象优化循环
使用生成器,在循环外部封装循环主体,完成一些必须在循环内部完成的工作。
例如,循环序列找到偶数,循环内部的操作完全可以写在生成器中,生成器yield
返回处理好的结果即可。
6. 使用itertools模块优化循环
6.1 product() --扁平化多层嵌套循环
from itertools import product
print(list(product([1, 2], [3, 4], [5, 6])))
#笛卡尔积
#[(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
6.2 islice() – 循环内隔行处理
islice(seq,start,end,step)
sep:输入流,相当于循环内容
start:循环开始位置
end:循环结束位置
step:循环间隔
6.3 takewhile() – 循环提前终止
takewhile(predicate,iterable)
在迭代对象iterable
过程中,不断使用当前iterable
的值作为参数,调用predicate
函数中,predicate
返回对应bool值,为True则继续循环,否则立刻终止。
7. 文件读取注意事项
常用做法 with+open:
with open(filename)
,这样做有两个好处:
(1)使用上下文管理器会自动关闭文件描述符。
(2)迭代文件对象时,内容一行一行返回,不会占用太多内存。
但同时也隐藏一些问题:
(1)当文件内容是一整行没有换行符的时候,会将整个文件作为一行内容返回处理,耗费巨大的资源。另外做法 while+read:
调用更底层的file.read(size)
方法,会立刻读取从当前游标位置向后读取size大小的内容,以字节为单位,1024*8代表每次读取8kb数据。做法三:iter:
iter(callable,sentinel)
通过这种方式调用iter会返回一个特殊的迭代器,迭代该迭代器时会不断返回调用callable
函数的结果,一旦结果等于sentinel
则迭代终止。