• 😶Captain_sir_Smil...
    2019-06-12
    我觉得这样会好理解很多,碰到yield后,暂停,再次调用next()时,从上次的位置开始执行
    def frange(start, stop, step):
        print('starting')
        x = start
        while x < stop:
            yield x
            x += step


    it = frange(10, 15, 0.5)
    print(next(it))
    print(next(it))
    print(next(it))


    输出结果:
    starting
    10
    10.5
    11.0
    11.5
    展开
    
     6
  • Kanner
    2018-06-12
    老师、这个yield还是没懂为什么能对浮点数进行叠加、而且我试了一下把yield换成print、输出的内容也是一样的呀

    作者回复: yield的主要用途是需要一个数据时,才产生一个,而不是把数据线一次性存入内存;相对于把数据提前定义成列表来使用,要极为节省系统资源。
    一般访问生成器要使用next方法,也可以使用list方法一次性讲将所有值读取出来,但是一次性读取出来就和列表一样了,失去自身的优势。

    
     5
  • 圣林
    2018-07-31
    谢谢老师的讲解,上上一课里面的“可选参数”和“可变长参数”,再加上本节课的迭代器和生成器,自己看书的时候看了好几遍都无法理解,当一看到老师的视频讲解后豁然开朗,有种通透的感觉,这几个概念不过如此嘛~

    作者回复: 是的,学习就是一种从不懂到懂,从陌生到熟悉的过程,但是要想透彻的掌握一门语言还要多了解它背后的原理和技术,继续努力吧

    
     3
  • .1nmm
    2018-09-27
    我把yield换成了print后有报错TypeError: 'NoneType' object is not iterable。
    而且出现的位置每次运行的都会不一样
     2
     2
  • jacy
    2018-09-06
    yeild的实现原理是怎样的呢,如何做到的暂存,是存放在当前的调用栈吗?

    作者回复: 带yield的函数我们称为迭代器,这种函数返回的是一个固定的对象,叫迭代器对象,它和return的最大区别是,如果你需要返回无限序列,return会产生一个巨大的列表,很明显存在内存限制问题。所以引入了yield返回一个固定长度的值。
    确实如你所说,python虚拟机有一个调用栈,以python3.7为例,在Python-3.7.0\Include\frameobject.h 17行定义了PyFrameObject结构体,用来保存最后执行的指令、异常和命名空间。
    当新创建一个迭代器时会调用Python-3.7.0\Objects\genobject.c 817行 PyGen_New(PyFrameObject *f) 函数。
    我们知道调用yield其实就是调用迭代器的next方法,也就是调用了gen_iternext(PyGenObject *gen)函数,最终调用的是152行的gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) 函数。
    这里的Py_INCREF(result)函数用于记录引用计数器并加一,
    *(f->f_stacktop++) = result 209行这里是参数压栈操作了。

    
     2
  • 硕杨Sxuya
    2018-09-16
    没有比较,不明白 yield 到底有什么区别。

    作者回复: 通常一个函数返回执行结果使用的是return关键字,但是在实际使用中发现如果函数返回的内容非常多而且是按顺序每次只使用一个元素的话,我们需要把结果再处理成可迭代对象,例如返回一个列表,我们要使用for..in...的形式再对返回结果做处理,这时候可以使用yield关键字来返回,有效的避免了一次返回数据过多,占用较多内存的问题。这就是为什么有了return还要产生yield的原因了。这里还有一些注意事项,使用yield关键字的函数叫做生成器,他返回的结果是可迭代对象,只能读取一次。更多的原理请参考stackoverflow : https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do

    
     1
  • Megahertz
    2018-08-10
    # 函数的迭代器和生成器

    list1 = [1, 2, 3]
    it = iter(list1)
    print(next(it))
    print(next(it))
    print(next(it))
    # print(next(it)) # StopIteration
    # fix me: 为什么try except 不能捕获异常呢
    try:
        print(next(it))
    except Exception as e:
        print(e)
    展开

    作者回复: 是可以捕获的,只是因为stopiteration异常没有额外的返回信息,导致你输出的e没有任何内容,让你误以为捕获失败,将e换成其他提示信息可以看到捕获正常

    
     1
  • 我要养只猫
    2018-07-15
    老师,我把yield i换成print(i)后,输出的结果中会掺杂 typeerror是怎么回事?

    作者回复: 需要看到你的完整代码和报错信息,如果是按照演示的程序修改,会报错为frange是非迭代对象,也就是没有yield没有迭代功能,不能使用for in的语法调用

    
     1
  • Rita
    2018-07-02
    为什么当我把step改成0.2的时候,输出结果变成
    10
    10.2
    10.399999999999999
    10.599999999999998
    10.799999999999997
    10.999999999999996
    11.199999999999996
    11.399999999999995
    11.599999999999994
    展开

    作者回复: 出现这样计算结果的原因是浮点数缺乏精确性导致的,如在python中计算 1+0.2+0.2+0.2,
    发现执行结果和你的经验不一样了吗?
    不止在python语言中存在这样的问题,凡是实数计算都会存在无限的精度跟有限的内存之间的矛盾
    在系统底层计算浮点数时是使用二进制经过了它的转换,就出现了你看到的“误差”
    要想精确计算可以使用Decimal库,就可以避免这种情况了
    from decimal import Decimal
    a = Decimal('1')
    b = Decimal('0.2')
    print(a+b+b+b)

    
     1
  • Dean_其
    2019-04-25
    老师咨询一下如果yield的作用是可以让函数停留在当次的迭代值,那么为什么我下面的代码执行一次的时候什么值的都没有,根据代码来看print应该至少显示值为1,而不会显示后面的值才对。
    除非我把frange(1,10,2)改为next(frange(1,10,2))就会输出值为1,求解
    def frange(start,stop,step):
        x = start
        while x < stop:
            print(x)
            yield x
            x += step
    frange(1,10,2)
    展开

    作者回复: 通过type()查看frange会发现,当你调用只会frange会变成<class 'generator'>类型,而生成器类型是不会自动执行的,必须用next() 或者list()取其中的元素,和你想的会按顺序执行不太一样

    
    
  • 王善鹏
    2019-03-30
    老师,c++中函数对传入的参数有引用和复制的区别,python中有吗?python中不使用全局变量的话,如果在函数内部对传入的参数初始化,函数外部会同步改变吗?

    作者回复: c++ 中有传参、传值、传址方式,python中没有,它传递的是变量的别名。
    这是python内部的变量机制,如: a=1 并不是将a的地址空间设置为1 ,而是 a存在一个地址空间, 1存在一个地址空间,然后让a指向1。
    当使用函数传参时,将形参指向1,如果需要对形参进行修改时,并不是将1做修改,而是重新创建一个对象,让形参指向新的对象。
    以上是对于不可变的对象的操作,那如果对象是可变的呢,则函数内部的修改,就会在函数外面看到变化了。
    这是个涉及python内部机制的一个问题,在了解了基础的python知识后,建议可以以变量作用范围作为切入点深入学习python

    
    
  • 稚者
    2019-02-19
    迭代器没有像Java那样的it.hasNext()方法吗?
    while it.hasNext():
        print(next(it))
    这样的?

    作者回复: 和java不一样,python的机制是它自己实现一个next() 方法来返回当前的元素 ,next(it)
    然后指向下一个元素的位置,当前位置没有元素时抛出StopIteration异常。

     try:
        while True:
            print it.next()
     except StopIteration:
         pass

    
    
  • Rita
    2018-07-02
    代码是这样:
    def func(start,stop, step):
        x=start
        while x<stop:
            yield x
            x+=step
    for i in func(10,20,0.2):
        print(i)
    展开
    
    
我们在线,来聊聊吧