python基础:可迭代的、迭代对象、迭代器、生成器

1、可迭代的、迭代器、生成器总结

 

迭代对象、迭代器、生成器的关系:

可迭代对象、可迭代器有什么区别?

  • 2者实现的方法不一致,可迭代对象只实现了__iter__方法,可迭代器实现__iter__和__next__方法,后者是前者的子集;
  • 内存分配方式不一致,可迭代对象会将全部的元素都放入内存,而可迭代器是随时用随时分配,会记录下当前运行的状态和信息,下一次调用元素时在分配。

 

2、可迭代的

可迭代的,iterable

直观上来说:序列类、容器类,都是可迭代的。

可迭代的可以理解为:内部实现了__iter__()方法,可通过调用__iter__()方法,取得下一个元素,如果没有下一个元素抛出异常:StopIteration

 

3、可迭代对象Iterable

定义:可迭代对象,是指内部实现了__iter__()方法的对象,__iter__()方法返回的是迭代对象自身。

判断:可迭代对象可通过instance(x, Iterable)来判断。可迭代对象都可以使用for循环迭代使用,但可使用for循环的未必是可迭代对象,因类中实现了__getitem__方法的对象,也可以被for循环迭代,但并不是可迭代对象。

可迭代对象包括:str、list、tuple、dict、set

基本数据对象中的str、list、tuple、dict、set是可迭代对象,但并不是迭代器,但是可以通过iter(iterable) 方法转换为迭代器。迭代器是可以通过next() 方法,不断的计算下一个迭代对象,直到没有数据时,抛出StopIteration异常。

from collections.abc import Iterable, Iterator

astr = ""

res = isinstance(astr, Iterable)

>> True

res = isinstance(astr, Iterator)

>> False

res = isinstance(iter(astr), Iterator)

>> True

 

4、迭代器Iterator

定义:可迭代器,是指内部实现了__iter__()和__next__()方法的对象。和可迭代对象相比,可迭代对象包含于迭代器中。__iter__() 返回迭代器对象,如果后面没有迭代对象,会报错StopIteration,__next__() 返回下一个迭代器对象。

判断:迭代器可通过instance(x, Iterator)来判断。

迭代器处理顺序:内部不断的调用__next__() 取得下一个元素,__iter__() 返回迭代器自身;如没有下一个元素,触发StopIteration异常。

 

5、生成器

迭代可以理解为循环处理,处理的对象比如列表或字典等,会存放在内存空间。但是,如果出现列表长度非常长等情况时,将所有的列表都存放在内存,并不是可取的方案,而生成器,可以解决这个问题:迭代处理,同时可做到随时用随时分配内存空间。

有2种方式可以得到生成器:1)列表生成器;2)带yield的函数

 

5.1、列表生成器

列表生产器的[] 修改为 (),如下面例子中,如果是[],mark只是一个列表,但当把[]改为()后,mark成了一个生成器。在输出mark,得到的是生成器。

mark = (x for x in [1, 2, 3, 4, 5])

>> <generator object <genexpr> at 0x10d69d580>

以上列表生成器,可以理解为,对列表[1, 2, 3, 4, 5]的迭代,每次只取一个元素使用,并保存当前的迭代位置,用以下次迭代,当没有元素后,会报错StopIteration。

怎样访问列表生成器中的元素?

  • next():基本上不会用到next()方法,用for循环来处理,也不用处理StopIteration异常。
  • for
# 使用next()得到生成器的下一个元素
mark = [1, 2, 3]
print(next(mark))
print(next(mark))
print(next(mark))
print(next(mark))
print(next(mark))
print(next(mark))

>> 1

>> 2

>> 3

>> StopIteration

# 使用for循环来迭代访问生成器中的元素
mark = (x for x in [1, 2, 3, 4, 5])
for i in mark:
    print(i)

 

5.2、yield

列表生成器,得到的生成器比较简单。当有较复杂的迭代逻辑时,可用生成器函数来实现。生成器函数是指:一个函数中,有yield关键字。 

可以理解为,生成器函数保存的是算法,每次迭代,都会计算下一个元素的值,如果没有下一个元素会抛出异常StopIteration。

 

5.2.1、和普通函数相比

1)调用方式不一致;next(g)和g.send(value)调用

  • 普通函数,func()表示调用函数func,此时会为函数中的数据分配栈空间,函数执行完后,分pop栈空间。
  • 生成器函数,g()并没有调用函数,而是生成一个生成器函数,调用生成器需使用next(g)或g.send(value),next(g)是每次返回生成器的下一个元素,g.send(value)是改写了生成器的返回,第1次调用生成器需使用next(g),后面可使用next(g)或g.send(value),因没有1次调用生成器,g.send(value)也不能改写生成器的返回。

2)从不存储任何取值,生成器是一个一个的生成值

def student():
    print("for test")
    m = yield 5
    print(m)
    d = yield 12

s = student()
print(next(s)) # 打印结果:for test  5
print(s.send(10)) # 打印结果: 10  12

解析以上例子:

  • s = student():并没有调用函数,只是得到一个生成器
  • print(next(s)):next(s)执行到yield 5停止,此时yield可以理解为return,遇到yield,会暂停在yield执行的右边,所以左边的赋值给m并没有执行,print(next(5))将打印出5
  • print(s.send(10)):再次调用生成器,从上次执行的地方继续执行。首先将取值赋值为m,而此时g.send(10)是将10这个参数直接覆盖之前的结果,将10赋值给m;在执行print(m)将打印出10,最后yiled 12暂停,返回12,print(s.send(10))将返回的12打印出来。

 

5.2.2、和return相比

  • 普通函数return后,函数执行完成,函数的栈空间释放。
  • yield,可以理解为生成器函数的返回,但只是暂时返回,将保存生成器函数的结果,下次在调用从上次执行结果处继续执行。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值