回归问题的本质,为什么要用yield而不是print
直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。
看看这个有什么区别
def item_iterator(embed_list):
for item in embed_list:
if isinstance(item, (tuple, list)):
# print(type(item_iterator(item)))
for item in item_iterator(item):
print(item)
else:
yield item
lst = (0, (1, 2), (3, (4, 5)))
for item in item_iterator(lst):
print("ok")
print("ok",item)
def item_iterator(embed_list):
for item in embed_list:
if isinstance(item, (tuple, list)):
# print(type(item_iterator(item)))
for item in item_iterator(item):
yield item
else:
yield item
lst = (0, (1, 2), (3, (4, 5)))
for item in item_iterator(lst):
print("ok")
print("ok",item)
区别很明显,print虽然可以输出,但是item_iterator是作为函数,而使用yield,item_iterator是作为迭代器,统一在for循环中,输出,更符合程序数据统一出口。简洁。
迭代器真是复杂。用pythontutor运行上面的例子,明白了中间那个for的作用。
写迭代,估计都要用到那个for。
基础概念
https://www.zhihu.com/question/20829330
http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html
如果还是不能理解,有很好的工具可以帮助调试。
http://pythontutor.com/visualize.html#mode=display
找到一篇好理解的文章
http://kissg.me/2016/04/09/python-generator-yield/
yield作为一个暂停恢复的点,代码从yield处恢复,又在下一个yield处暂停.可见,在一次next()(非首次)或send(value)调用过程中,实际上存在2个yield,一个作为恢复点的yield与一个作为暂停点的yield.因此,也就有2个yield表达式.send(value)方法是将值传给恢复点yield;调用next()表达式的值时,其恢复点yield的值总是为None,而将暂停点的yield表达式的值返回.为方便记忆,你可以将此处的恢复点记作当前的(current),而将暂停点记作下一次的(next),这样就与next()方法匹配起来啦.
可迭代对象(Iterable)是实现了__iter__()方法的对象,通过调用iter()方法可以获得一个迭代器(Iterator)
迭代器(Iterator)是实现了__iter__()和__next__()的对象
for ... in ...的迭代,实际是将可迭代对象转换成迭代器,再重复调用next()方法实现的
生成器(generator)是一个特殊的迭代器,它的实现更简单优雅.
yield是生成器实现__next__()方法的关键.它作为生成器执行的暂停恢复点,可以对yield表达式进行赋值,也可以将yield表达式的值返回.yield迭代器理解顺序1.素数
def prime_sieve(n):
flags = [True] * n
flags[0] = flags[1] = False
for i in xrange(2, n):
if flags[i]:
yield i
for j in xrange(2, (n - 1) / i + 1):
flags[i * j] = False
for p in prime_sieve(100):
print p
2.两个yield + 循环
def item_iterator(embed_list):
for item in embed_list:
if isinstance(item, (tuple, list)):
item_iterator(item)
#当在第4行递归使用item_iterator(item)时,它并不是一个函数的递归调用,而是一个generator object
else:
yield item
lst = (0, (1, 2), (3, (4, 5)))
for item in item_iterator(lst):
print item
正确
def item_iterator(embed_list):
for item in embed_list:
if isinstance(item, (tuple, list)):
for i in item_iterator(item)
yield i
else:
yield item
3.next(it)
4.理解
对一个序列进行全排列
内部for-》外部for-》外部for
外部for循环,两次,你看
for i in range(len(li)):
li[0], li[i] = li[i], li[0]
如果li只要两个元素,那么会循环两次,[1,2]会变成[1,2]和[2,1]
例子
1.python 学习笔记 第二版
def framework(logic):
try:
it = logic()
s = next(it)
print "[FX] logic: ", s
print "[FX] do something"
it.send("async:" + s)
except StopIteration:
pass
def logic():
s = "mylogic2"
r = yield s
print r
print framework(logic)
def fibonacci():
a,b=0,1
while True:
yield b
a, b = b, a + b
fib=fibonacci()
print fib.next()
print fib.next()
print fib.next()
print [fib.next() for i in range(10)]
2.python 迭代器 生成器 - jihite
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n = 1
for n in fab(5):
print n
a, b = b, a + b 赋值结果,a=b,b=a+b,引用的都是前面的值
>>> a = 1
>>> b = 2
>>> t = b, a + b
>>> t
(2, 3)
>>> a, b = t
>>> a
2
>>> b
3
注意t是一个tuple
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
c = consumer("alex")
c.next()
c.send("韭菜馅")
3.对一个序列进行全排列
def permutations(li):
if len(li) == 0:
yield li
else:
for i in range(len(li)):
li[0], li[i] = li[i], li[0]
for item in permutations(li[1:]):
#有for循环,就会输出yield内容
#[li[0]] + item+permutations(li[1:])
yield [li[0]] + item
for item in permutations(range(3)):
print item
怎么理解呢?
先外部,后全部内部#0 0返回的数据以及数据类型
# [1,2,3] 先执行第一个for循环
# 然后执行第二个for循环
# 变成[1,2],再执行一次第一个for循环,
#然后执行第二个for循环
#变成[2],#然后执行第二个for循环
#完成最后一层,退回到第一个for循环最新理解
从前到后,而不是从后到前
先执行外部for,然后内部for,如果内部for有很多个,那么内部for-》外部for-》外部for
这样的顺序
最后执行的话,item输出为none,然后变成0,1,2,0,2,1.
就是这样。
[0, 1, 2]
[0, 2, 1]
[1, 0, 2]
[1, 2, 0]
[2, 0, 1]
[2, 1, 0]
其实,还有这种for循环,可以用最小的个数来理解,比如2个。
了解下输出[0,1,2]和[0,2,1]的过程
1.[0,1,2]
li=[0,1,2] i=0
li=[1,2] i=0
li=[2] i=0
li empty list
li=[2] item empty list
return value 2
li=[1,2] item=[2] i=0
return [1,2]
li=[0,1,2] item=[1,2]
return [0,1,2]
2.[0,2,1]
li=[0,1,2] item=[1,2]
li=[1,2], item=[2] i=0
.............
li=[2,1] item=[2] i=1
li=[1]
li=[2,1],item=1
................
return [0,2,1]
可以看出li,到了li[1:]后,执行那个for循环语句,交互数值,这步出现了2个结果
然后外层循环是3个,所以结果是6种结果。
print(list(itertools.permutations(horses)))
参考https://my.oschina.net/passer007/blog/483681
Python Iteration,itertools(Python迭代器,itertool个人总结)
yield返回的值是什么
4.def addlist(alist):
for i in alist:
yield i + 1
print "next"
yield i + 2
##会输出两次,多个yield会输出多次
alist = [1, 2, 3, 4]
for x in addlist(alist):
print x,
5.def permutations(li):
if len(li) == 0:
yield li + [1]
else:
for i in range(len(li)):
li[0], li[i] = li[i], li[0]
for item in permutations(li[1:]):
yield [li[0]] + item + [9]
for item in permutations(range(3)):
print item
yield li,那么说明li已经是个迭代器了
for循环有几次就循环几次
yield li = yield []
6.next(it) it为函数,这就更加清楚了import time
def A():
while True:
print("----我是A函数---")
yield
time.sleep(0.5)
print("AAAAAAAAAAAA")
def B(c):
while True:
print("----我是B函数---")
next(c)
#next会不断从yield处暂停和恢复
time.sleep(0.5)
print("BBBBBBBBBBBB")
if __name__ == '__main__':
a = A()
B(a)
7.八皇后问题