美文网首页
Python yield关键字

Python yield关键字

作者: Assassin_1397 | 来源:发表于2020-01-11 16:35 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Python yield关键字

          本文链接:https://www.haomeiwen.com/subject/lgavactx.html