Python中的生成器
通过列表生成式,我们可以直接创建一个列表。但是受内存限制,列表容量肯定是有限的。如果创建一个包含1000万个元素的列表,不仅会占用很大的储存空间,我们仅仅只需要访问前面的几个元素,那后面的大多数元素占用的空间都白白浪费了。
在Python中一边循环一边计算的机制,称为生成器:generator
,它具有一下特点:
- 1.只有在当前调用时才会生成相应的数据
- 2.只记录当前位置
- 3.只有一个.__next()__方法
#列表生成式
def fun(i):
return i*i
l=[i for i in range(10)] #列表生成式
list=[fun(i) for i in range(10)] #可以是函数,实现更多的功能
l[1] #列表生成式,我们可以采用切片来取后面的值,但是生成器就不行了
#生成器
g=(i for i in range(10)) #返回的是一个地址,数据还不存在generator object
for k in g:
print(k)
# print(g.__next__()) 你可以使用.__next()__方法一个一个的调用生成器
# print(g.__next__())
#跟列表生成式的区别就是你不调用,它根本就没有
斐波那契数列著名的斐波那契数列,除第一个元素和第二个元素外,任意一个数都可以由前两个数相加得到:1,1,2,3,5,8,13,21,34……,我们可以采用函数把它打印出来
def fun(max):
n, a, b = 0, 0, 1
while n<max:
print(b,end=' ')
a,b = b,a+b
n+=1
fun(10)
注意
a=0
b=1
# a = b
# b = a + b
# print(a,b) 结果(1,2)
a,b=b,a+b
print(a,b) #结果(1,1)
#两者不可以混迹,你也可以单独分开采用断点尝试一下
上面我们只是用函数,把斐波那契数列打印出来了,它离生成器只有一步之遥,要把fun函数变成generator,只需要把print(b )修改为yield b即可。
def fun(max):
n, a, b = 0, 0, 1
while n<max:
yield b
a,b = b,a+b
n+=1
print(fun(10)) #这样就变成了生成器,你可以采用.__next()__方法来获取一个值试试
f=fun(10)
print(f.__next__())
print(f.__next__())
print("我可以随时插进去")
print(f.__next__())
print(f.__next__())
print("我还可以随时出来")
print(f.__next__())
我们可以发现,在使用函数打印斐波那契数列时,是一下子全部打印完的,我们不能在中途做任何事情,而生成器则不同了,我们可以在取值时,做一些事情。一个函数中存在yield,它就不在时函数了,是一个生成器。我们采用.__next()__方法一个一个的调用生成器,很好,fun(10)有10次,我们调用100次呢,会发生什么,会出现StopIteration异常报错
def fun(max):
n, a, b = 0, 0, 1
while n<max:
yield b
a,b = b,a+b
n+=1
return '我是一个小草'
f=fun(6)
while True:
try:
g=next(f) #内置方法等同于.__next()__
print('g:',g)
except StopIteration as e:
print('出错了...',e)
break
我们添加了一个return返回值,然后还抓取了StopIteration报错信息,出错就会显示return的返回值
Python中的迭代器
我们首先要知道,可以用for循环的数据类型有:List列表、Tuple元组、Dict字典、Set集合、Str字符串、Bytes字节、生成器generator、带yield的generator函数
。这些可以直接作用于for循环的对象
称之为可迭代对象(Iterable)
.你可以使用isinstance()函数来判断是否是Iterable对象
。
可以被next()
(.__next()__)函数调用并不断返回下一个值的对象称之为迭代器(Iterator)
。
可迭代对象和迭代器不是一回事,同样我们也可以使用isinstance()来判断一个对象是否是Iterator对象
,注意两者不可混记!
#由于我是用的是3.7版本的,所以需要从collections.abc中导入
#如果你从collections导入会报错,但是不碍事,在3.8就会废除collectons.abc
from collections.abc import Iterable #Iterable可迭代对象
from collections.abc import Iterator #Iterator迭代器
#判断是否为可迭代对象,返回结果都是可迭代对象
print(isinstance([1,23,445,5],Iterable))
print(isinstance((12,32,14,21,31),Iterable))
print(isinstance('我是一个字符串',Iterable))
print(isinstance({'name':'zjj','love':'wff'},Iterable))
print(isinstance({'zjj','wff','xxk','zgp'},Iterable))
#判断是否为迭代器
print(isinstance( (i for i in range(10)),Iterator)) #迭代器
print(isinstance( [1,23,3,4],Iterator))
print(isinstance( {'zsda',1232,'zjj'},Iterator))
print(isinstance( ('ZJJ','awdadw') ,Iterator))
print(isinstance( 'ZJJ' ,Iterator))
#你也可以使用dir()方法来查看该对象所有的方法,只要含有__next__,就是迭代器
f=(i for i in range(10))
print(dir(f))
以上代码可以发现,生成器都是迭代器(Iterator),但是可迭代对象不是迭代器,因为它们不符合迭代器的定义,但你可以使用iter()函数,把可迭代对象变成迭代器.
iter( )iter( )函数可以把可迭代对象转换为迭代器,那么同样就可以使用.__next()__方法来取值
from collections.abc import Iterator #Iterator迭代器
#判断是否为迭代器
print(isinstance( (i for i in range(10)),Iterator)) #迭代器
print(isinstance( iter([1,23,3,4]),Iterator))
print(isinstance( iter({'zsda',1232,'zjj'}),Iterator))
print(isinstance( iter(('ZJJ','awdadw')) ,Iterator))
print(isinstance( iter('ZJJ') ,Iterator))
迭代器(Iterator)可以表示一个无限大的数据流,而使用List列表是永远不可能存储全体自然数的。
2. 本站不保证所提供下载的资源的准确性、安全性和完整性,资源仅供下载学习之用!如有链接无法下载、失效或广告,请联系客服处理!
3. 您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容资源!如用于商业或者非法用途,与本站无关,一切后果请用户自负!