日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Python筆記003-生成器和生成器表達式

系統 2289 0

Python筆記003-生成器和生成器表達式

以下是我學習《流暢的Python》后的個人筆記,現在拿出來和大家共享,希望能幫到各位Python學習者。

首次發表于: 微信公眾號:科技老丁哥,ID: TechDing,敬請關注。

本篇主要知識點:

  1. 生成器使用yield做關鍵字,一次只返回一個值給調用者,然后暫停執行,其作用是:節省內存空間。

  2. 生成器可以用next()函數,也可以用for迭代的方式獲取元素值,中間還可以用close()來隨時終止生成器。

  3. 生成器表達式可以認為是一種特殊的生成器,其代碼更簡潔,更容易理解,且和別的函數結合會更加靈活。

1. 生成器

生成器是Python中一個特殊的程序,用于控制循環的迭代行為。相對于一般函數用return來一次性返回所有值,生成器使用yield關鍵字,一次只返回一個值。

這樣的設計有很大的好處:在數據處理時,如果函數return出來的是一個非常大的數組,那么會非常占用內存,有時會報MemoryError的錯誤,而使用yield后一次僅僅返回一個元素值,可以優化內存占用的情況。

從這種角度來講,生成器函數每一次調用都返回一個元素值,這種特性使得生成器長得像函數,但行為卻像迭代器。

            
              
                def
              
              
                squares
              
              
                (
              
              x
              
                )
              
              
                :
              
              
                # 計算0-x的所有數的平方
              
              
                #     return [i*i for i in range(x)] # 普通寫法,一次返回一個list,包含所有元素
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              x
              
                )
              
              
                :
              
              
                yield
              
               i
              
                *
              
              i 
              
                # 生成器:一次只返回一個值
              
              
                print
              
              
                (
              
              squares
              
                (
              
              
                5
              
              
                )
              
              
                )
              
              
                # 
                
              
              
                # 獲取生成器中的元素值
              
              
                for
              
               value 
              
                in
              
               squares
              
                (
              
              
                5
              
              
                )
              
              
                :
              
              
                # 行為類似于迭代器,循環獲取元素值
              
              
                print
              
              
                (
              
              
                'value: '
              
              
                ,
              
              value
              
                )
              
            
          

生成器并不像一般的函數,它返回一個值后,生成器函數會自動掛起,等到下一次調用時(使用其內部成員方法 __next__ 來實現),再返回到這個函數中繼續執行。

所以要想獲取生成器的元素值,需要通過成員方法next()來進行,比如:

            
              square_five
              
                =
              
              squares
              
                (
              
              
                5
              
              
                )
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 0
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 1
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 4
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 9
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 16
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 報錯:StopIteration: 超過yield的所有元素
              
            
          

next()函數每次執行時,都會繼續執行掛起的生成器函數,直到執行完畢。

生成器的這種特點被稱為"延遲計算"或"惰性求值(Lazy evaluation)",可以有效的節省內存。惰性求值實際上是體現了協同程序的思想。

雖然生成器的這種行為類似于迭代器,但兩者有較大差別,迭代器不具備這種執行-暫停-再執行-再暫停的特性,所以迭代器不具有延遲計算,沒有協同程序的思想。

使用延遲計算后,可以極大的節省內存,比如對大文件進行讀取操作時,可以用下列生成器方法:

            
              
                ## 讀取大文件的生成器方法:
              
              
                def
              
              
                load_big_file
              
              
                (
              
              file_path
              
                )
              
              
                :
              
              
    BLOCK_SIZE 
              
                =
              
              
                1024
              
              
                with
              
              
                open
              
              
                (
              
              file_path
              
                ,
              
              
                'rb'
              
              
                )
              
              
                as
              
               f
              
                :
              
              
                while
              
              
                True
              
              
                :
              
              
            block 
              
                =
              
               f
              
                .
              
              read
              
                (
              
              BLOCK_SIZE
              
                )
              
              
                if
              
               block
              
                :
              
              
                yield
              
               block 
              
                # 一次只加載一個block到內存中,避免MemoryError
              
              
                else
              
              
                :
              
              
                return
              
            
          

生成器除了用next()函數來處理之外,還可以用close()來隨時退出生成器。如下代碼:

            
              
                ## 使用close()可以隨時退出生成器
              
              
square_five
              
                =
              
              squares
              
                (
              
              
                5
              
              
                )
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 0
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 1
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # 4
              
              
square_five
              
                .
              
              close
              
                (
              
              
                )
              
              
                # 退出生成器
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # Error: StopIteration:
              
              
                print
              
              
                (
              
              
                next
              
              
                (
              
              square_five
              
                )
              
              
                )
              
              
                # Error: StopIteration:
              
            
          

2. 生成器表達式

從形式上來看,生成器表達式和列表推導式很像,僅僅是將列表推導式中的[]替換為(),但是兩者差別挺大,生成器表達式可以說組合了迭代功能和列表解析功能。

生成器表達式可以認為是一種特殊的生成器函數,類似于lambda表達式和普通函數。但是和生成器一樣,生成器表達式也是返回生成器generator對象,一次只返回一個值。

            
              
                # 上面的squares函數可以改寫為:
              
              
                # 列表推導式的寫法是:
              
              
squares_list
              
                =
              
              
                [
              
              i
              
                *
              
              i 
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                5
              
              
                )
              
              
                ]
              
              
                # 一次性返回整個list
              
              
                print
              
              
                (
              
              
                '列表推導式:'
              
              
                ,
              
              squares_list
              
                )
              
              
                # 列表推導式: [0, 1, 4, 9, 16]
              
              
                # 生成器表達式:
              
              
squares2
              
                =
              
              
                (
              
              i
              
                *
              
              i 
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                5
              
              
                )
              
              
                )
              
              
                # 生成器表達式一次返回一個值
              
              
                print
              
              
                (
              
              
                '生成器表達式:'
              
              
                ,
              
              squares2
              
                )
              
              
                # 生成器表達式: 
                
                  
                    print
                  
                  
                    (
                  
                  
                    next
                  
                  
                    (
                  
                  squares2
                  
                    )
                  
                  
                    )
                  
                  
                    # 0
                  
                  
                    print
                  
                  
                    (
                  
                  
                    next
                  
                  
                    (
                  
                  squares2
                  
                    )
                  
                  
                    )
                  
                  
                    # 1
                  
                  
                    print
                  
                  
                    (
                  
                  
                    next
                  
                  
                    (
                  
                  squares2
                  
                    )
                  
                  
                    )
                  
                  
                    # 4
                  
                
              
            
          

生成器表達式是一種特殊的生成器,所以它也有生成器的特性,可以使用for循環來獲取元素值,for循環內部自動調用了next()函數來執行。

            
              
                # generator對象可以直接用for來獲取所有元素值
              
              
squares2
              
                =
              
              
                (
              
              i
              
                *
              
              i 
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                5
              
              
                )
              
              
                )
              
              
                # 生成器表達式就是一個generator對象
              
              
                for
              
               i 
              
                in
              
               squares2
              
                :
              
              
                print
              
              
                (
              
              
                'i: '
              
              
                ,
              
              i
              
                )
              
              
                # 上面可以簡寫為:
              
              
                [
              
              
                print
              
              
                (
              
              
                'i: '
              
              
                ,
              
              i
              
                )
              
              
                for
              
               i 
              
                in
              
              
                (
              
              i
              
                *
              
              i 
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                5
              
              
                )
              
              
                )
              
              
                ]
              
            
          

生成器表達式如果作為某個函數的參數,則可以省略掉(),直接使用即可,eg:

            
              
                ## 如果生成器表達式整個作為某個函數的參數,可以省略掉()
              
              
max_value
              
                =
              
              
                max
              
              
                (
              
              i
              
                *
              
              i 
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                5
              
              
                )
              
              
                )
              
              
                # 計算生成器的所有元素中的最大值
              
              
                print
              
              
                (
              
              max_value
              
                )
              
              
                # 16
              
            
          

首次發表于: 微信公眾號:科技老丁哥,ID: TechDing,敬請關注。

本文所有代碼都已經上傳到我的github,歡迎下載

參考資料:

  1. 《流暢的Python》,Luciano Ramalho (作者) 安道 , 吳珂 (譯者)。

更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 梁山县| 平度市| 甘德县| 宕昌县| 天祝| 天等县| 工布江达县| 富源县| 吐鲁番市| 鹤壁市| 遂平县| 平遥县| 津南区| 犍为县| 云梦县| 贡嘎县| 大城县| 潜山县| 交城县| 随州市| 明溪县| 清丰县| 兴城市| 望城县| 星子县| 浦北县| 民权县| 大安市| 马尔康县| 广汉市| 达州市| 潮州市| 阜城县| 廊坊市| 方山县| 九龙城区| 泸西县| 怀柔区| 昌平区| 普格县| 乌审旗|