生成器的优势
- 生成器是一种特殊的迭代器,不用去写一个有初始化_ _init_ _,_ _iter_ _,_ _ next__ 代码的可读性变高,更易读了,直接在普通函数上写
- 生成器它同样是不需要上来就开辟一大片空间,按需分配是最好的解答,你要多少,函数就一次一次地给你多少,一次执行了就等待下一次调用,然后再传回来值
例子:
遍历列表中的所有元素
第一个版本:
lista = [[1, 2], [3, 4], [5, 6]]
def flatten(list):
for sublist in lista:
for i in sublist:
print(i)
flatten(list)
结果:
1
2
3
4
5
6
这是最最最简单的方法,我写一个函数,然后在函数里面直接打印出所有的元素,两次for 用起来,美滋滋,su服~,但是这段代码最尬的地方就是,复用性比较差,我要是要在别的地方用,比如我要给每个元素都加上1怎么办?这个函数我还能直接拿过来用吗?
第二个版本:解决复用性
lista = [[1, 2], [3, 4], [5, 6]]
def flatten(list):
temp_list = []
for sublist in lista:
for i in sublist:
temp_list.append(i)
return temp_list
print(flatten(lista))
结果:[1, 2, 3, 4, 5, 6]
这段看上去不错哎~解决了复用性问题,比如我要再对这些数进行操作,就可以直接在返回的这个列表上进行操作了~美滋滋,但是问题又来了,我这一下子返回整个列表,我要是数字贼多,一下子不就崩了嘛?对的~接下来就轮到迭代器登场咯~
突然发现一个小问题,进行小补充:
如果列表有一个元素它不是嵌套的呢?
lista = [[1, 2], [3, 4], [5, 6], 5]
def flatten(list):
temp_list = []
for sublist in lista:
try:
for i in sublist:
temp_list.append(i)
except TypeError:
temp_list.append(i)
return temp_list
print(flatten(lista))
结果: [1, 2, 3, 4, 5, 6, 6]
用一个异常处理来解决。当不是可迭代对象的时候,也就是说单个数字不能拆分啦,就直接添加进列表里面,继续下一次循环。那么又有问题了。。如果里面有多层嵌套呢?
改进:应该可以用递归把
lista = [[1, 2], [3, 4], [5, 6], 5, [1, [2, 3]]]
def flatten(list):
temp_list = []
for sublist in list:
try:
for i in flatten(sublist):
temp_list.append(i)
except TypeError:
temp_list.append(sublist)
return temp_list
print(flatten(lista))
下面用生成器,对于这种for 用生成器真的是方便啊!而且还好用
def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested
lista = [[1, 2], 2, [3, 4], 5, [6, 7], [1, [2, 3]]]
for i in flatten(lista):
print(i, end=' ')
结果:1 2 2 3 4 5 6 7 1 2 3
好用到哭啊,有没有啊!
最后补充一下自己对异常的又一次新的理解:
当出现异常的时候(单个数字不是可迭代对象,不能再进行拆分)yield返回nested,返回到哪里去了呢?这里for element in flatten(sublist)这里的函数调用,就是in后面的,一开始不大清楚,用pass替代了yield element之后发现,怎么捣鼓也不输出值。
然后又想了:抓到值之后呢?不是返回了一个数字嘛?在for element in flatten(sublist)里面不报错呢?神奇的地方!因为yield自动把nested变成了列表啦!请看!
print(type(nested))
yield nested
print(type(nested))
结果:
< class ‘int’>
< class ‘list’>
又来补充咯~
python基础书上说嘛,当遇到了字符串的时候会进入无限循环的,导致程序直接失败而崩溃,通过在stackoverflow上的提问,然后再加上自己的想法,最终得出了一个正确的方法:如下
def flatten(nested):
try:
if isinstance(nested, str):
for i in nested:
yield i
else:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested
lista = [[1, 2], 3, ['abc',[1, 'abc']]]
for i in flatten(lista):
print(i)
结果:
1
2
3
a
b
c
1
a
b
c
这是一个成功解决含有字符串的版本。如果是字符串直接yield 字符串里面的每个元素,这样最终完成了这个。很奇妙吧~