zoukankan      html  css  js  c++  java
  • Python中的生成器与yield

    对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧。

    可迭代对象

    当你创建一个列表的时候,你可以一个接一个地读取其中的项。一个接一个地读项就叫做迭代

    >>> mylist = [1, 2, 3]
    >>> for i in mylist:
    ... print(i)
    1
    2
    3
    

    mylist就是一个可迭代对象。你使用列表推导式时,就创建了一个列表,也就是一个可迭代对象:

    >>> mylist = [x*x for x in range(3)]
    >>> for i in mylist:
    ... print(i)
    0
    1
    4
    

    任何可以用“for...in...”操作的事物都是可迭代对象;列表,字符串,文件……

    这些可迭代对象很方便,因为你可以随意地访问它们,但是你把所有的值都保存在内存中。如果你有大量的数据的话,这就不是你想要的了。

    生成器

    生成器是迭代器,但是你只可以对它们进行一次迭代。这是因为你没有在内存中存储所有数值,它们动态地生成值

    >>> mygenerator = (x*x for x in range(3))
    >>> for i in mygenerator:
    ... print(i)
    0
    1
    4
    

    跟上面的例子基本一样,除了用()代替了[]。但是,你不能第二次执行for i in mygenerator,因为生成器只能使用一次;它计算出0,然后忘掉0并计算1,最后是计算4,一个接一个地进行。

    Yield

    Yield是一个像return一样的关键字,只不过函数返回的是一个生成器:

    >>> def createGenerator():
    ... mylist = range(3)
    ... for i in mylist:
    ... yield i*i
    ...
    >>> mygenerator = createGenerator() # 创建一个迭代器
    >>> print(mygenerator) # mygenerator是一个对象!
    <generator object createGenerator at 0xb7555c34>
    >>> for i in mygenerator:
    ... print(i)
    0
    1
    4
    >>> for i in mygenerator:
    print(i)
    
    
    >>> 
    

    这个例子里的生成器没什么用,但是如果你知道你的函数会返回大量的数据,而你只需要对这些数据读取一次时,那就变得很有用了。

    要掌握yield你必须理解当你访问函数的时候,你写在函数体中的代码并没有执行。这个函数只是返回了迭代器对象,这一点很微妙。

    然后,每次for语句使用生成器的时候,你的代码就会运行。

    然后是最难的部分:

    for语句第一次调用从你的函数中创建的迭代器对象时,它就会运行你函数中的代码,从开始一直到它碰见yield,然后它就返回这个循环中的第一个值。之后,每一次的调用都会再一次运行你写在函数里的循环,然后返回下一个值,直到没有值可以被返回。

    一旦函数运行但是没有再碰到yield,生成器就被认为是空的。这可能是因为循环已经结束了,或者因为不再满足if/else条件了。

    控制生成器耗尽

    >>> 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(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 # crisis is coming, no more money!
    >>> print(corner_street_atm.next())
    <type 'exceptions.StopIteration'>
    >>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
    >>> print(wall_street_atm.next())
    <type 'exceptions.StopIteration'>
    >>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
    >>> print(corner_street_atm.next())
    <type 'exceptions.StopIteration'>
    >>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
    >>> for cash in brand_new_atm:
    ... print cash
    $100
    $100
    $100
    $100
    $100
    $100
    $100
    $100
    $100
    ...
    

    这个在很多方面都有用,比如控制对某个资源的访问。

    Itertools,好帮手

    itertools模块包含操作可迭代对象的特殊函数。想要复制一个生成器?连接两个生成器?把嵌套列表中的数据整理到一个列表中?不创建另一个列表就直接Map/Zip?

    那就import itertools

    例子?那我们看看4马比赛中所有可能的到达顺序(全排列):

    >>> horses = [1, 2, 3, 4]
    >>> races = itertools.permutations(horses)
    >>> print(races)
    <itertools.permutations object at 0xb754f1dc>
    >>> print(list(itertools.permutations(horses)))
    [(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)]
    

    理解迭代的内部机制

    迭代是一个暗含可迭代对象(实现了__iter__()方法)和迭代器(实现了__next__()方法)的过程。可迭代对象是任何你可以从中得到迭代器的对象。迭代器是可以让你对可迭代对象进行迭代的对象。

    更多信息请参考how does the for loop work

  • 相关阅读:
    input 去除边框
    分页封装
    python后端继承序列化,不同访问形式返回不同结果
    解决vue前端不显示自定义字段
    Vue 获取后端多对多关联表信息
    vue 前段增删改查代码规范
    前段增删改查的应用
    ant-design-vue基础
    python 后端 数据库的创表及增删改查 简单使用
    配置Uwsgi+Nginx+Django+Vue
  • 原文地址:https://www.cnblogs.com/GuoYaxiang/p/6215685.html
Copyright © 2011-2022 走看看