return返回的是一个元组(默认),而yield每次调用只返回一个数值,毫无疑问,使用return空间开销比较大,尤其是操作巨量数据的时候,操作一个大列表时间开销也会得不偿失
yield 生成器相比 return一次返回所有结果的优势:
(1)反应更迅速
(2)更节省空间
(3)使用更灵活
yield和return的关系和区别:带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器并不会从foo函数的开始执行,只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。
可以看出,yield 输出的是一个对象,相当于是一个容器,想取什么数据就取出什么,而return 只会返回一个值,且return后面的代码不会执行。
迭代器iterables
迭代器就是你创建一个列表,你可以一个个的读取。
lists,strings,files 等都是可以迭代的,只要你可以用for ... in ...,但是你必须把它们的值放到内存里,当它们有很多值时就会消耗太多的内存.
lists = [1,2,3,4]
mys = [x*x for x in range(3)]
for i in mylist:
print(i)
生成器generator
生成器也是迭代器,即迭代器包括生成器,但是你只能迭代他们一次,因为他们不是全部在内存中,他们只有在调用的时候在内存中生成。
mygenerator = (x*x for x in range(3))
for i in mygenerator:
print(i)
但是生成器是用()而不是用[]
还有你不能用for i in mygenerator第二次调用生成器
因为其计算完就丢弃。
yield
yield的用法和关键字return差不多,下面的函数将会返回一个生成器
def creategenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = creategenerator() # 创建生成器
>>> print(mygenerator) # mygenerator is an object!
>>> for i in mygenerator:
... print(i)
当for语句第一次调用函数里返回的生成器对象,函数里的代码就开始运作,直到碰到yield,然后会返回本次循环的第一个返回值.所以下一次调用也将运行一次循环然后返回下一个值,直到没有值可以返回.
一旦函数运行并没有碰到yeild语句就认为生成器已经为空了.原因有可能是循环结束或者没有满足if/else之类的.
extend()是一个列表对象的方法,它可以把一个迭代对象添加进列表
生成器的好处
- 你不需要读这个值两次
- 你能得到许多孩子节点但是你不希望他们全部存入内存.
- 这种方法之所以能很好的运行是因为python不关心方法的参数是不是一个列表.它只希望接受一个迭代器,所以不管是strings,lists,tuples或者generators都可以!
- 这种方法叫做duck typing,
控制迭代器穷尽
class bank(): # 让我们建个银行,生产许多atm
... crisis = false
... def create_atm(self):
... while not self.crisis:
... yield "$100"
>>> hsbc = bank() # 当一切就绪了你想要多少atm就给你多少
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = true # cao,经济危机来了没有钱了!
>>> print(corner_street_atm.next())
>>> wall_street_atm = hsbc.create_atm() # 对于其他atm,它还是true
>>> print(wall_street_atm.next())
>>> hsbc.crisis = false # 麻烦的是,尽管危机过去了,atm还是空的
>>> print(corner_street_atm.next())
>>> brand_new_atm = hsbc.create_atm() # 只能重新新建一个bank了
>>> for cash in brand_new_atm:
... print cash
迭代进阶 itertools
itertools.count(start=0, step=1)
from itertools import *
for i in izip(count(1), ['a', 'b', 'c']):
print i
(1, 'a')
(2, 'b')
(3, 'c')
itertools.cycle(iterable)
from itertools import *
i = 0
for item in cycle(['a', 'b', 'c']):
i = 1
if i == 10:
break
print (i, item)
(1, 'a')
(2, 'b')
(3, 'c')
(4, 'a')
(5, 'b')
(6, 'c')
(7, 'a')
(8, 'b')
(9, 'c')
itertools.repeat(object[, times])
from itertools import *
for i in repeat('over-and-over', 5):
print i
over-and-over
over-and-over
over-and-over
over-and-over
over-and-over
itertools.chain(*iterables)
将多个迭代器作为参数, 但只返回单个迭代器, 它产生所有参数迭代器的内容, 就好像他们是来自于一个单一的序列.
from itertools import *
for i in chain([1, 2, 3], ['a', 'b', 'c']):
print i
1
2
3
a
b
c
itertools.groupby(iterable[, key])
from itertools import groupby
qs = [{'date' : 1},{'date' : 2}]
[(name, list(group)) for name, group in itertools.groupby(qs, lambda p:p['date'])]
out[77]: [(1, [{'date': 1}]), (2, [{'date': 2}])]
>>> from itertools import *
>>> a = ['aa', 'ab', 'abc', 'bcd', 'abcde']
>>> for i, k in groupby(a, len):
... print i, list(k)
...
2 ['aa', 'ab']
3 ['abc', 'bcd']
5 ['abcde']
itertools.permutations
horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
...