import time
from collections import Iterator
from collections import Iterable
列表、字符串、字典、元组、集合等凡是可以直接作用于for循环的对象统称为可迭代对象:Iterable
而可以用next的方法调用并不断返回下一个值的对象称为迭代器:Iterator
可以使用iter()函数把list、dict、str等Iterable变成Iterator:
print(isinstance({},Iterable))
print(isinstance('abc',Iterable))
print(isinstance({},Iterator))
print(isinstance('abc',Iterator))
print(isinstance(iter({}),Iterator))
print(isinstance(iter('abc'),Iterator))
#输出:
'''
True
True
False
False
True
True
'''
1、迭代 当创建一个列表对象后,可以一个接一个读取列表中的值,这个过程就叫做迭代。
new_list = [1,1,2,2]
for i in new_list:
#print(i, end = ' ')
# 输出:
'''
1 1 2 2
'''
#print(i)
#输出:
'''
1
1
2
2
'''
#列表推导表达式
mylist作为可迭代对象,在使用前先存储所有值,规模越大,
存储时间就越长,所占内存就越大,如下
'''
mylist = [2*x+1 for x in range(1000000)]
for i in mylist:
print(i, end=' ')
'''
2、生成器(Generator) 也是可迭代对象,生成器就是一个迭代器。
生成器用来解决的内存资源消耗的问题。即取即用,不占内存。依次取用,不可跳取。
create_g=(2*x+1 for x in range(10))
print(create_g) #<generator object <genexpr> at 0x00AE4220>
使用一对方括号创建的是列表对象,而使用一对圆括号创建的就是迭代器对象,
如果直接输出,会输出迭代器对象的地址,只有通过for...in...语句或调用
迭代器的相应方法才能输出迭代器对象中的值。而且第二次对迭代器对象进行迭代,
什么都不会输出,这是因为迭代器只能被迭代一次,
而且被迭代的值使用完,是不会再保存在内存中的。
'''
for i in create_g:
print(i, end=' ')
print('\n'+"第二次迭代分割线")
for i in create_g:
print(i, end=' ')
'''
#通过next()函数(or __next__())获得generator的下一个返回值:
'''
print(create_g.__next__())
print(create_g.__next__())
print(next(create_g))
'''
#输出:
'''
1
3
5
'''
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,
直到计算到最后一个元素,没有元素可取时,抛出StopIteration的错误
yield 生成器对象是通过使用yield关键字定义的函数对象,因此,生成器也是一个函数。
通过yield语句创建生成器函数。如创建斐波那契数列:
def fib(max):
n,a,b=0,0,1
while n<max:
a,b=b,a+b
n+=1
m0=yield a
#先执行yield a,再将值传给m0,此处的m0只能通过send函数传值
print('yield a % s' % a)
print('yield m0 % s' % m0)
m1=yield 'try'
print('yield try m1 % s' % m1)
return "Finished!"
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,
在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
'''
t1 = fib(3)
x = next(t1)
print('next x %s' % x)
y = t1.send(10)
print('next y %s' %y)
z = next(t1)
print('next z %s' % z)
'''
#输出:
'''
next x 1
yield a 1
yield m0 10
next y try
yield try m1 None
next z 1
yield a 1
yield m0 None
'''
运行过程说明:
第一步:r = fib(3),实例化一个生成器对象
第二步:调用next() ,遇到yield 暂停,返回值1,赋值给x
第三步:打印x,>>next x 1
第四步:传值10,在暂停处接受值10,把10传给m0,继续运行,打印a的值,遇到第二个yield,
将字符串try赋值给y
第五步:打印y,>>next y try
第六步:调用next() ,接着之前yield 'try'继续执行,没有值传给m1,
后面也没有yield的语句,打印m1为None,
此时,n,a,b分别为1,1,1,继续执行while,经过第二次公式,n,a,b为2,1,2,将a值即1传给z。
#生成器并行
food = ["莲蓉馅", "紫薯馅", "豆沙馅", "蛋黄馅"]
def consumer(name):
print("%s准备吃月饼了!" % name)
while True:
yuebing = yield 'n'
此处的=号只能通过send函数来传值,而不是将yield语句后的字符串n值传给yuebing
print("[%s]月饼来了,被[%s]吃了!" % (yuebing, name))
def producer(name):
c1 = consumer('哥哥')
c2 = consumer('姐姐')
c1.__next__()
c2.__next__()
print("%s开始准备做月饼啦" % name)
for i in range(6):
print("第%d次做了%s个月饼" % (i + 1, len(food)))
stt=time.time()
time.sleep(i+2) #做月饼所花时间
endt=time.time()
print("花了%s时间"%(endt-stt))
f1 = food[i]
c1.send(f1)
_next__()或next()或send()函数都是在上次执行的地方继续执行,
直到执行到yield语句,或者该生成器函数执行完
food.append(f1)
c2.send(food[i])
f1的值没变,所以哥哥姐姐吃的是同一种馅的月饼
producer('妈妈')
报错:DeprecationWarning: Using or importing the ABCs from ‘collections’ instead of from ‘collections.abc’ is deprecated since Python 3.3, and in 3.9 it will stop working
from collections import Iterator
翻译:Deprectionwarning: 使用或导入‘ collections’而不是‘ collections.abc’中的 abcs,自 python 3.3以来就不推荐使用,在3.9中,它将停止使用 collections import iterator
即将语句:
from collections import Iterator
from collections import Iterable
改为:
from collections.abc import Iterator
from collections.abc import Iterable
就不会报错了。