列表生成式&生成器&迭代器:生成器都是迭代器,迭代器不一定是生成器

https://www.cnblogs.com/yuanchenqi/articles/5769491.html
https://www.cnblogs.com/yyds/p/6281453.html
列表生成式:顾名思义,列表生成式就是一个用来生成列表的特定语法形式的表达式。
基础语法格式

[exp for iter_var in iterable]

生成器与列表生成式对比
既然通过列表生成式就可以直接创建一个新的list,那么为什么还要有生成器存在呢?

因为列表生成式是直接创建一个新的list,它会一次性地把所有数据都存放到内存中,这会存在以下几个问题:

内存容量有限,因此列表容量是有限的;
当列表中的数据量很大时,会占用大量的内存空间,如果我们仅仅需要访问前面有限个元素时,就会造成内存资源的极大浪费;
当数据量很大时,列表生成式的返回时间会很慢;
而生成器中的元素是按照指定的算法推算出来的,只有调用时才生成相应的数据。这样就不必一次性地把所有数据都生成,从而节省了大量的内存空间,这使得其生成的元素个数几乎是没有限制的,并且操作的返回时间也是非常快速的(仅仅是创建一个变量而已)。

例如:s=(x*2 for x in range(100)#range(start, stop[, step]),o开始
print(next(s))#等价于s.next() in py2: s.next() 结果为0;
print(next(s))#等价于s.next() in py2: s.next() 结果为4;

生成器(Generator)
生成器就是可迭代对象;本质就是一个函数
从名字上来看,生成器应该是用来生成数据的。

  1. 生成器的作用
    按照某种算法不断生成新的数据,直到满足某一个指定的条件结束。生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。
  2. 生成器的构造方式
    构造生成器的两种方式:

使用类似列表生成式的方式生成 (2*n + 1 for n in range(3, 11))
使用包含yield的函数来生成
如果计算过程比较简单,可以直接把列表生成式改成generator;但是,如果计算过程比较复杂,就只能通过包含yield的函数来构造generator。

说明: Python 3.3之前的版本中,不允许迭代函数法中包含return语句。

3. 生成器构造实例#生成器&生成器对象指的是同一个意思,

生成器在创立的时候就已经决定了能计算出的值得个数,一旦调用next的次数超出这个数量就会报错
1.使用类似列表生成式的方式构造生成器
g1 = (2n + 1 for n in range(3, 6))#这是列表生成式产生的生成器(2n + 1 for n in range(3, 6)),还没有产生数据
2.使用包含yield的函数构造生成器
def my_range(start, end):##my_range()是生成器,生成器也是函数,range是函数名
for n in range(start, end):
yield 2*n + 1 #带有yield的生成器
g2 = my_range(3, 6)
print(type(g1))
print(type(g2))

输出结果:


  1. 生成器的执行过程与特性
    生成器的执行过程:
    在执行过程中,遇到yield关键字就会中断执行,下次调用则继续从上次中断的位置继续执行。

生成器的特性:
只有在调用时才会生成相应的数据
只记录当前的位置
只能next,不能prev

5. 生成器的调用方式或者方法

要调用生成器产生新的元素,有两种方式:

调用内置的next()方法

使用循环对生成器对象进行遍历(推荐)
for循环内部做了三件事:
1.调用对象的iter方法,返回一个迭代器对象

  1. while:
                try:
                      i=next (list_Iterator)
                       except  stopIteration:
                                    break
    

调用生成器对象的send()方法
send():
f().send(None)#等价于next(f())

s=(2*n + 1 for n in range(3, 11))
print(s)#生成器 at 0x000001E63FFE0DD0>
print(next(s))#等价于s.next() in Py2: s.next()
print(next(s))
print(next(s))
print(next(s))#工作过程:# 迭代iterable中的每个元素;# 每次迭代都先把结果赋值给iter_var,然后通过exp得到一个新的计算值;# 最后把所有通过exp得到的计算值以一个新列表的形式返回。
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))#StopIteration
可见,使用next()方法遍历生成器时,当超出遍历范围,最后是以抛出一个StopIeration异常终止。

实例2:使用循环遍历生成器

g1 = (2*n + 1 for n in range(3, 6))#3,4,5
for x in g1:
print(x)
输出结果是
7
9
11
可见,使用循环遍历生成器时比较简洁,且最后不会抛出一个StopIeration异常。因此使用循环的方式遍历生成器的方式才是被推荐的。
需要说明的是:如果生成器函数有返回值,要获取该返回值的话,只能通过在一个while循环中不断的next(),最后通过捕获StopIteration异常

实例3:调用生成器对象的send()方法

def my_range(start, end):
for n in range(start, end):
ret = yield 2*n + 1
print(ret)
g3 = my_range(3, 6)

print(g3.send(None))
print(g3.send('hello01'))
print(g3.send('hello02'))
输出结果:
7
hello01
9
hello02
11
print(next(g3))
print(next(g3))
print(next(g3))
输出结果:
7
None
9
None
11

结论:
next()会调用yield,但不给它传值
send()会调用yield,也会给它传值(该值将成为当前yield表达式的结果值)
需要注意的是:第一次调用生成器的send()方法时,参数只能为None,否则会抛出异常。当然也可以在调用send()方法之前先调用一次next()方法,目的是让生成器先进入yield表达式。
https://www.cnblogs.com/alex3714/articles/5143440.html

可迭代对象(Iterable)

我们经常在Python的文档中看到“Iterable”这个此,它的意思是“可迭代对象”。那么什么是可迭代对象呢?

可直接用于for循环的对象统称为可迭代对象;本质上是有iter方法的是可迭代对象(Iterable)。
满足迭代器协议:
1.内部有next方法
2.内部有iter()方法

目前我们已经 知道的可迭代(可用于for循环)的数据类型有,本质上是内部有iter方法!!!:
li=[1,2,3]: iterable(内部有iter方法)>>>>>>
i=iter(li):list_Iterator#i是迭代器对象
集合数据类型:如list、tuple、dict、set、str等生成器(Generator)
可以使用isinstance()来判断一个对象是否是Iterable对象:

from collections import Iterable
print(isinstance([], Iterable))

你可能感兴趣的:(列表生成式&生成器&迭代器:生成器都是迭代器,迭代器不一定是生成器)