Python中yield关键字解释
这篇文章关于python的yield关键字。并且文章中会解释什么是yield,generator和iterables。
解释yield之前,我们先来理解一下迭代器(iterables)和生成器(generators)。
Iterables
当创建一个list时候,你可以遍历它,那么这就叫迭代器:
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
...
1
2
3
>>>
mylist是一个可迭代对象。当你用list comprehension语法创建列表时,也是可以迭代的:
>>> mylist = [x * x for x in range(3)]
... print (i)
0
1
4
当你使用"for ... in ..."操作对象时,这些对象都是可迭代的,例如:list,str,files,set等。这些可迭代对象有个优点就是你可以多次去遍历,但是也有个缺点这些对象都是在内存中的,当数据量很大时你不得不去考虑内存使用情况。
Generators
生成器也是一种迭代器,但是与迭代器不同的是,你只能遍历一次,这是因为生成器不会把值保存在内存当中,它在你遍历的过程中生成值。
>>> mygen = (x*x for x in range(3))
>>> for i in mygen:
... print(i)
...
0
1
4
>>>
遍历生成器和mylist相同,只是把[]改为了()。但是不同之处你不能对mygen进行二次遍历
>>> mygen = (x*x for x in range(3))
>>> for i in mygen:
... print(i)
...
0
1
4
>>> for i in mygen:
... print(i)
...
>>>
Yield
Yield在python中是一个关键字,就像return,但是不同的是yield返回的是一个generator。
>>> def fun_with_yield():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> gen = fun_with_yield()
>>> for i in gen:
... print(i)
...
0
1
4
>>>
还有一点需要注意,虽然你调用了函数(fun_with_yield())但是函数体的内容压根就没有执行,只有你通过生成器去遍历时,函数体才真正执行
困难点:
当for第一次去遍历函数fun_with_yield返回的generator时,它会从函数fun_with_yield的第一行去执行直到遇到了yield关键字,然后它会返回函数for循环中的第一个值 0 * 0 = 0。然后它会继续执行循环中剩余代码,并进入fun_with_yield函数的下一次循环,直到没有值可以返回为止。接下来看一个用yield实现去重列表的例子。
>>> def my_unique_list(items):
... unique_items = []
... for item in items:
... if item not in unique_items:
... yield item
... unique_items.append(item)
...
>>> mylist = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(my_unique_list(mylist))
[1, 5, 2, 9, 10]
>>>
一旦函数被调用了,且没有yield被执行,那么generator就空了。你可以理解为循环遍历结束了或者没有"if/else"满足条件了。
generator控制展示
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "$100"
...
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print (next(corner_street_atm))
$100
>>> print (next(corner_street_atm))
$100
>>> print ([next(corner_street_atm for cash in range(5))])
[<generator object Bank.create_atm at 0x00000140541C9570>]
>>> print ([next(corner_street_atm) for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # crisis is coming, no more money!
>>> print(next(corner_street_atm))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
>>> print(next(wall_street_atm))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> hsbc.crisis = False # Trouble is, even post-crisis the ATM remains empty
>>> print(next(wall_street_atm))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> print (next(brand_new_atm))
$100
>>> print(next(wall_street_atm))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
在资源控制方面yield也大有作为。
Itertools,你最好的朋友
Itertools module包含了处理iterables的特殊函数。想要复制generator?连接两个generators?用一行代码实现对一个嵌套list分组?不用创建另一个list实现 Map/Zip?
实现这些功能,仅仅需要
import itertools
需要演示一下?让我们看一个计算4匹赛马的排列组合数
>>> horse = [1, 2, 3, 4]
>>> import itertools
>>> races = itertools.permutations(horse)
>>> print (races)
<itertools.permutations object at 0x000002BC7966F830>
>>> print(list(races))
[(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
>>>
了解iteration底层实现原理
Iteration实际实现了iterables的iter()方法和iterators 的next()方法。Iterables指的是任何可被遍历的对象。Iterators are objects that let you iterate on iterables.
原文地址:https://pythontips.com/2013/09/29/the-python-yield-keyword-explained/
参考文档:
https://python3-cookbook.readthedocs.io/zh_CN/latest/c01/p10_remove_duplicates_from_seq_order.html
https://python3-cookbook.readthedocs.io/zh_CN/latest/c01/p03_keep_last_n_items.html
网友评论