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则迭代终止。