1. 你??吹?Python 代碼中的 yield 到底是什么鬼?

        共 1789字,需瀏覽 4分鐘

         ·

        2019-12-20 23:28


        之前給大家說過,久久會解鎖一篇 VIP 中的文章給大伙樂呵樂呵,其實是被吐槽沒有試看文。




        41be5ac619184a0658612a7f936697d7.webp





        好吧,今天就是這么出其不意攻其不備,就隨便挑選一篇出來給你瞧瞧貨色:?yield 到底是干屌的?



        首先我們來看下這兩個列表的區(qū)別:




        a17e2dd68c8e85229d434795668f2a09.webp



        可以看到, list_1 是 [i for i in range(20)] ,而 list_2 是 (i for i in range(20)),主要區(qū)別就是一個是 [] , 一個是 (),而后者就是生成器。

        可以看到,當我們去執(zhí)行 list_2 的時候,輸出結果是一個 generator(生成器)對象。

        我們可以通過 next() 去調用這個生成器里面的元素:


        a79bfb9150220f29d0179a39b47ea94f.webp




        我想到這里你會有點疑惑,就是它們之間有什么區(qū)別?

        我們這樣,來計算一下以下這兩個列表生成所需要的時間:

        list_1 = [i for i in range(66666666)]list_2 = (i for i in range(66666666))

        我們分別把它們放到方法里面執(zhí)行,然后用裝飾器的方式對它們各自的方法執(zhí)行時間做個記錄:


        2fe8797df1c34473298e1a7ffcc66b97.webp



        執(zhí)行結果如下:


        91fedca38466440cba4daf9f9af8a2f2.webp


        你會發(fā)現(xiàn),方法二,也就是生成器生成的列表 list_2 所消耗的時間遠低于 list_1。

        這是因為使用列表生成式生成的列表,是固定的,也就是說,當我們執(zhí)行 [i for i in range(66666666)] 的時候, list_1 這個列表所封裝的元素個數(shù)就是 66666666 -1 個。

        而生成器生成的 list_2 就不是這樣,它是記錄了一定的算法規(guī)則,比如我們這里的 for i in range(66666666) 就是不斷的 +=1 ,生成器只要記住這個規(guī)則就可以了,不需要將全部的數(shù)據(jù)都直接一股腦的裝進 list_2 ,而是等到我們需要的時候,我們去調用的時候,它再去算一下,然后把相應的數(shù)據(jù)返回給我們。

        這,就是生成器,記住一點,它是根據(jù)一定的規(guī)律算法生成的,當我們去遍歷它的時候,它可以通過特定的算法不斷的推算出相應的元素,邊運行邊推算結果,從而節(jié)省了很多空間。

        體會下下面這兩者的區(qū)別:


        ba3c14328da9053705d2aa5a8a52d88e.webp



        知道了什么是生成器之后,咱們再來看看這個魔法關鍵詞:yield。

        yield 和 return 有點相似,return 這個關鍵詞你應該很熟悉吧,在函數(shù)中只要執(zhí)行到這個關鍵詞,就會返回相應的結果并且終止函數(shù)的執(zhí)行:

        8904d58a832dfdc20f771a6440223c37.webp



        很好理解,這里返回 3 而不會繼續(xù)返回 hahahahah。

        那么 yield 又是怎么樣的呢?咱們繼續(xù)看:


        f963602a4ca152b4e7960c8086be95e7.webp


        在這里面我們定義了一個 foo 方法,并且在里面定義了好幾個 yield ,可是當我們調用這個方法的時候,居然跟什么都沒有輸出。

        那么我們來看看調用了這個 foo 函數(shù)之后得到的是什么類型:

        ffcb52c261ad0fafc1d72dba4cfa033e.webp



        可以看到,它是一個生成器!

        是的,一個函數(shù)里面如果被定義了 yield ,那么這個函數(shù)就是一個生成器。

        我們可以通過 next 方法來使用這個生成器:

        d236c65f584b74df7e0ad04d1d2e63ef.webp



        可以看到,當我們第一次調用的時候,遇到第一個 yield 的時候就跳出函數(shù)了,第二次調用的時候就是從第 1 個 yield 開始,第三個 yield 結束,以此類推。直到 next 沒有數(shù)據(jù)之后報 StopIteration。

        既然它是一個生成器,那么我們就可以遍歷它,我們具體打印出每個具體的元素,看看是什么:

        935bbef197e60688931079a9d8a1026f.webp



        可以看到我們這里得到的都是 None ,這是因為我們 yield 的時候沒有返回具體數(shù)據(jù),我們可以這樣:

        4790d863fd78ab075865529451a30a89.webp



        這樣我們就可以得到的生成器里面具體的元素了。

        不過呢,我們一般不會這么寫,我剛剛說了,生成器是根據(jù)一定的規(guī)律算法生成的列表,當我們去遍歷它的時候,它可以通過特定的算法不斷的推斷出相應的元素,邊運行邊推算結果,節(jié)省空間。

        所以 yield 一般會在 for 循環(huán)語句以一定的規(guī)則生成,舉一個最簡單的例子,生成這么些偶數(shù):



        80ce922752a8f3a60e6d7e227f146053.webp



        這樣我們在調用 foo 的時候就會得到一個生成器,然后就可以直接遍歷使用。另外,yield 后面可以跟常用的數(shù)據(jù)類型,比如 string,int,dict:


        43840cf1e2174963830d00d8927bfa95.webp


        那么當你下次去調用相應的函數(shù)就會得到這樣的 generator,于是就可以:OMG,根據(jù)對應的規(guī)則遍歷它!?


        ok,以上就是生成器和 yield 的用法,你以后還會經??吹剿纳碛埃覀兿禄匾?,peace!




        1fb66ea2bd06c9c48bc56866a25aae72.webp


        掃一掃

        學習 Python 沒煩惱




        瀏覽 39
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 99热免费在线观看 | 有码无码中文字幕 | 一级特黄60分钟高清免费观看 | 一级少妇女片 | 影音先锋三级资源 |