生成器&迭代器
列表生成式
把列表[0,1,2,3,4,5,6,7,8,9]中的每个元素加1
a = [i+1 for i in range(10)]
print(a)
结果
[1,2,3,4,5,6,7,8,9,10]
这样的写法就叫做列表生成式
生成器
- 生成器——迭代器
- 生成器函数——本质上就是我们自己写的函数
- 列表生成式
列表是可迭代的,但不是迭代器
l = [1,2,3,4,5,6]
for i in l: # 生成了一个迭代器
print(i)
if i == 2:
break
for i in l: # 又生成了一个迭代器
print(i)
结果
1
2
1
2
3
4
5
6
生成器的作用:当列表中的元素个数很多时,甚至大于内存容量,查看列表中元素,如果一次性将所有元素装入内存,显然不合适。这时可以用生成器来解决这一问题,生成器执行时一次装入部分元素到内存,且具有记忆功能,可以从停止的地方接着往下执行。
def func():
for i in range(2000000):
yield '衣服%s' % i
f = func()
f1 = func()
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f1.__next__())
结果
衣服0
衣服1
衣服2
衣服0
从上面的代码中我们可以看到,f 和 f1 是两个互不干扰的生成器。
yield 类似于 return ,返回一个生成器,是生成器函数中特有的
f.next()和f.iter()是对结果进行操作的内置函数
def func(): # 生成器函数
for i in range(2000000):
yield '衣服%s' % i
f = func()
count = 0
for i in f: # 打印 衣服1-5
print(i)
count += 1
if count>5:
break
print(f.__next__()) # 打印 衣服6
for i in f: # 打印 衣服7-11
print(i)
count += 1
if count>10:
break
结果
衣服0
衣服1
衣服2
衣服3
衣服4
衣服5
衣服6
衣服7
衣服8
衣服9
衣服10
衣服11
从以上代码中我们可以看出,生成器函数随用随停,再用的时候会从断点继续往下执行。
示例
def tail(filename):
f = open(filename, encoding='utf8') # 以读方式打开,不用刻意写mode='r'
while True: # 保持监听
line = f.readline().strip() # readlines()生成列表,不太合适;read()可以但是开销大
if line:
yield line
g = tail('监听文件')
for i in g:
if 'python' in i:
print('****', i)
迭代器
可以直接作用于for循环的数据类型有:
- 一类是:list、tuple、dict、set、str、f=open()、range()、enumerate
- 另一类是:generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:iterable。
可以使用isinstance()判断一个对象是否是Iterable对象
而生成器不当可以作用于for循环,还可以被next()函数不断调用并返回下一个值,知道最后抛出StopIteration错误表示无法继续返回下一个值了。
- 可以被next()函数调用并不断返回下一值的对象称为迭代器:Iterator对象
Iterable可迭代的 ——> _ iter_ #只要含有_iter_方法的都是可迭代的
[]._ iter_() 迭代器 ——> _ next_ #通过next可以从迭代器中一个一个取值
只要含有_iter_方法的都是可迭代的 ——Python可迭代协议
迭代器协议:只要同时含有_ iter_和_ next_方法的函数就是迭代器
做一个测试:
from collections.abc import Iterable
from collections.abc import Iterator
class A:
def __iter__(self):pass
def __next__(self):pass
a = A()
print(isinstance(a, Iterable)) # 判断是否可迭代
print(isinstance(a, Iterator)) # 判断是否是一个迭代器
结果
True
True
显然由因为class A中定义了iter和next方法,所以新创建的对象a是可迭代的,同时也是一个迭代器。
下面把两个方法分别注释一下,我们看一下结果
from collections.abc import Iterable
from collections.abc import Iterator
class A:
def __iter__(self):pass
#def __next__(self):pass
a = A()
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
结果:
True # 是可迭代的
False # 不是迭代器
from collections.abc import Iterable
from collections.abc import Iterator
class A:
#def __iter__(self):pass
def __next__(self):pass
a = A()
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
结果:
False # 不可迭代
False # 不是迭代器