Python生成器

生成器

通过列表生成式,我们可以直接创建一个列表。但是受内存限制,列表容量肯定是有限的。

而且,创建一个很多很多元素的列表,不仅占用很大的内存空间,如果我们仅仅访问前几

元素,那后面绝大多数的元素占用的空间就白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那多好!这样就不必浪费空间了,这样

你好我好大家好。

在Python中,这种一边循环一边计算的机制,称为生成器:generator

要创建一个generator,有很多种方法。

1)只要把一个列表生成式的[]改为(),就创建了一个generator。

L = [i * iforiinrange(5)]

print(L)#[0, 1, 4, 9, 16]

g = (i * iforiinrange(5))

print(g)# at 0x111136ca8>

创建L和g的区别仅在于最外层[]和(),L是一个list而g是一个genratot。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

我们可以通过  next(g)挨个拿其中的元素,最后一个取完之后再进行 next()操作会

报错(StopIteration)。

一个一个取是在太繁琐,我们可以用for循环,因为genertor是一个可迭代对象。

g = (i * iforiinrange(5))

foriing:

print(i) #用for循环来迭代,并且不需要关心StopIteration报错。

2)用函数来实现。

比如,斐波那契数列:1,1,2,3,5,8,13,21,34....

用列表生成式写不出来,但是我们可以用函数把它打印出来:

deffib(number):

    n, a, b =0,0,1

    whilen < number:

        print(b)

        a, b = b, a + b

        n = n +1

    return'OK!'

print(fib(5))

结果:

1

1

2

3

5

OK!

我们可以看出从第一个元素开始,推算出后续任意的元素。很像generator。

要把fib函数变成generator,只需要把print(b)改为yieldb就可以了:

deffib(number):

    n, a, b =0,0,1

    whilen < number:

        yieldb

        a, b = b, a + b

        n = n +1

    return'OK!'

print(fib(5))#

注意:

这里难理解的就是generator和函数的执行流程是不一样的。

函数是顺序执行,遇到return语句或者最后一行函数语句就

返回。

                注意:函数创建一次生成一个生成器,所以我们会将创建的生

                    成器赋值给一个变量。如果直接用函数本身这个生成器,

                    我们没用一次生成一个新的生成器对象,所以,我们一

                    般都将创建的生成器赋给一个变量。

generetor的函数,在每次调用 next()的时候执行,遇到

yield语句返回,再次执行时从上次返回的yield语句处继续

执行。

例子:

defodd():

    print('step 1')

    yield1

    print('step 2')

    yield(3)

    print('step 3')

    yield(5)

f = odd()

print(next(f))

print(next(f))

print(next(f))

结果:

step1

1

step2

3

step3

5

执行三次后再执行 next(f) 就会报错了。

可以看到odd不是普通函数,而是generator遇到yield就会中断

下次又继续执行,执行三次后已经没有yield可以执行,所以再执

行 next(f) 就会报错了。最后的yield后面一般不写东西。

把函数改为generator后,我们基本不这么用 next()来获取下一个返回值

而是直接使用for循环来迭代。

比如上面的fib函数。

deffib(number):

    n, a, b =0,0,1

    whilen < number:

        yieldb

        a, b = b, a + b

        n = n +1

    return'OK!'

foriinfib(5):

    print(i)

结果:

1

1

2

3

5

注意:用for循环调用generator时,发现拿不到generator的return

语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误

返回值包含在StopIteration的value中。

(关于如何捕获,异常处理见。)

    接下来我们来看send⽅方法, send和next()一样都可以让生成器执行到下一个yield.

        例子;

            defeat():

                print("我吃什么啊")

                a =yield"馒头"

                print("a=",a)

                b =yield"⼤大饼"

                print("b=",b)

                c =yield"韭菜盒⼦子"

                print("c=",c)

                yield"GAME OVER"

            gen = eat()# 获取⽣生成器器

            ret1 = next(gen)

            print(ret1)

            ret2 = gen.send("胡辣汤")

            print(ret2)

            ret3 = gen.send("狗粮")

            print(ret3)

            ret4 = gen.send("猫粮")

            print(ret4)


            结果:

                我吃什么啊

                馒头

                a= 胡辣汤

                ⼤大饼

                b= 狗粮

                韭菜盒⼦子

                c= 猫粮

                GAME OVER


        send和next()区别:

            1.send()和next()都是让生成器向下走一次

            2.send可以给上一个yield的位置传递值,不能给最后一个yield发送值.

                在第一次执行生成器代码的时候不能使用send()



        三道题:

            <1>

            defadd(a, b):

                returna+b

            defTest():

                foriinrange(4):

                    yieldi

            g = Test()

            fornin[2,10]:

                g = (add(n, i)foriing)

            print(list(g))


            结果:

                [20,21,22,23]

            <2>

            deffunc():

                print('1')

                yield 'This is one step'

                print('2')

                yield 'This is two step'

                print('3')

                yield 'This is theree step'

            it = func()#函数返回生成器

            print(list(it))


            结果:

            1

            2

            3

            ['This is one step', 'This is two step', 'This is theree step']


            <3>

            deffunc():

                print(111)

                yield222

            g = func()# 生成器g

            g1 = (iforiing)# 生成器g1. 但是g1的数据来源于g

            g2 = (iforiing1)# 生成器器g2. 来源g1

            print(list(g)) # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕.

            print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了了. g1 也就没有数据了

            print(list(g2))# 和g1同理


            结果:

                111

                [222]

                []

                []

    Form zero to hero

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,430评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,406评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,834评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,543评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,547评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,196评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,776评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,671评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,221评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,303评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,444评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,134评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,810评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,285评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,399评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,837评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,455评论 2 359

推荐阅读更多精彩内容

  • 1.什么是生成器 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一...
    一只写程序的猿阅读 943评论 0 4
  • Python列表生成式 列表推导式的一般语法 这种语法等价于以下代码 下面举一些列表推导式的栗子: Python中...
    So_ProbuING阅读 1,287评论 0 0
  • 生成器的概念 生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到Stop...
    teitiyuu阅读 1,289评论 0 0
  • 生成器 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含10...
    ztfdeveloper阅读 162评论 0 1
  • ​ 前面已经学习过迭代器了,也知道生成器本质上也是一个迭代器,生成器是用来创建Python序列的一个对象,可以...
    张氏小毛驴阅读 192评论 1 0