python快速学习系列(7):迭代器

本文深入解析Python中的迭代器协议与生成器概念,详细阐述迭代器的实现原理及生成器的优势,包括如何利用yield关键字简化迭代器的实现,以及生成器在节省内存和处理无限数据流方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代器协议
1.迭代器协议
·迭代器是一个对象
·迭代器可以被next()函数调用,并返回一个值
·迭代器可以被iter()函数调用,并返回迭代器自己
·连续被next()调用时返回一系列的值
·如果到了迭代的末尾,则抛出StopIteration异常
·迭代器也可以没有末尾,只要被next()调用,就一定会返回一个值
·python中,next()内置函数调用的是对象的__next__()方法
·python中,iter()内置函数调用的是__iter__()方法
·一个实现了迭代器协议的对象可以被for语句循环迭代直到终止

1)只要一个对象实现了__next__()方法,就可以被next()函数调用

class XIterator:
    def __next__(self):
        return 'hello world'
def main()
    x_it = XIterator()
    [print(next(x_it)) for i in range(3)]
#结果是打印hello world 3次

2)for语句的内部实现

for element in iterable:
    #do somthing with element

#create an iterator object from that iterable
iter_obj = iter(iterable)  #相当于从一个可迭代器里返回一个可迭代对象
#infinite loop
while True:
    try:
        #get the next item 
        element = next(iter_obj)
        #do somthing with element  也就是说,我们平时写for语句都是从这里开始写,之前和之后的都是解释器完成的     
    except StopIteration:
        #if StopIteration is raised , break from loop
        break

说明:
for语句里用的是iterable(可迭代对象),而非iterator(迭代器)
for语句执行的第一个操作是从哪一个iterable生成一个iterator
for语句的循环体其实是靠检测StopIteration异常来中断的
要想被for语句迭代需要三个条件:iter(),next(),StopIteration

3)一个标准的迭代器的写法:有__init__,next,iter,StopIteration

class XIterator:
    def __init__(self):
        self.elements = list(range(5))
    def __next__(self):
        if self.elements:
            return self.elements.pop()
        else:
            raise StopIteration
    
    def __iter__(self):
        return self

def main()
    x_it = XIterator()
    for x in x_it:
        print(x)

2.Generator
·迭代器很有用,但是实现起来有些繁琐,没关系,生成器来帮你
·生成器在保持代码简洁优雅的同时,自动实现了迭代器协议
1)实现生成器的方式一:yeild Expression

def f():
    yield 1
    yield 2
    yield 3
def main():
    f_gen = f()
    for x in f_gen:
        print(x)

关键字yield和return的区别:yield是暂停,稍后继续,并会自动实现StopIteration;而return是直接终止

2)实现生成器方式二:Generator expression

 [print(x) for x in (x ** 2 for x in range(5))]
#后面()内的表达式就是生成器表达式,即list comprehension的[]变成()就可

不要小看任何看似微小的区别:

sum([x ** 2 for x in range(1000000)])
sum(x ** 2 for x in range(1000000))

第一行:先生成一个长度为1000000的列表,然后在进行就和–>内存爆炸
第二行:其实是一个生成器,只是由于sum本身具有()而省略了(),这里的操作是聚合,即生成一个求和,生成一个求和(几乎不占内存)

也就是说,如果list存在的价值仅仅是迭代的话,用generator要好得多

3.为什么需要生成器
·相比迭代器协议,实现生成器的代码量小,可读性高
·相比在List中操作元素,直接使用生成器能节省大量内存
·有时候我们会需要写出一个无法在内存中存放的无线数据流
·可以建立生成器管道(多个生成器链式调用)

1)用生成器表示全部的斐波那契数列

def fibonacci():
    temp = [1,1]
    while True:
        temp.append(sum(temp))
        yield temp.pop(0)  #yield是实现生成器的关键字

2)通过生成器管道模块化处理数据

def fibonacci():
    temp = [1,1]
    while True:
        temp.append(sum(temp))
        yield temp.pop(0) 

def dataflow():
    for x in fibonacci():
        yield x ** 2
if __name__ == '__main__':
    for x in dataflow():
        print(x)
        if x > 10000:
            break
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值