<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python入門系列34 - 推導(dǎo)式與生成器

          共 3232字,需瀏覽 7分鐘

           ·

          2020-01-27 23:20

          Python入門系列34

          f5e2b202c03457f8597f6001cf34f090.webp

          推導(dǎo)式與生成器


          本篇閱讀時間約為 6 分鐘。


          1

          前言


          從本篇開始,進(jìn)入 Python 的技巧篇,介紹下編程時比較 pythonic 的寫法,有些寫法會非常簡潔,比如本文要介紹的推導(dǎo)式。


          推導(dǎo)式在各大教程中最常見的是列表推導(dǎo)式,但實際上不僅僅是列表可以進(jìn)行推導(dǎo),集合、字典都有著自己相應(yīng)的推導(dǎo)式。當(dāng)然,像廖雪峰老師寫的教程中,對應(yīng)的叫法是列表生成式,下面讓我們來一一看下。


          2

          案例需求


          老規(guī)矩,依然先給出一個案例的場景,通過此場景來介紹代碼的編寫與實現(xiàn)思路。


          案例場景:


          現(xiàn)有一個 list ,其中包含著一堆數(shù)字,比如 1- 10。若需要將其中的每個數(shù)字都進(jìn)行平方操作,最終放回 list。此段程序如何編寫呢?


          簡單思考一下,看過入門系列之前案例的童鞋們,在沒學(xué)習(xí)列表推導(dǎo)式之前??隙芟氲絻煞N方法。


          1. 用 for 循環(huán)遍歷每個元素節(jié)點,在 for 循環(huán)中進(jìn)行平方操作,最后在放回到原有 list 中。


          2. 使用 Python 內(nèi)置函數(shù) map 來實現(xiàn),第一個參數(shù)傳入一段計算平方的邏輯函數(shù),第二個參數(shù)傳入原有包含 1-10 的 list 即可。


          1 和 2 的實現(xiàn)思路有了,代碼就不在書寫了,忘記的同學(xué)可以去翻看下高階函數(shù)的那篇文章。


          下面介紹下,如何使用列表推導(dǎo)式來完成上述需求。


          3

          列表推導(dǎo)式


          代碼實現(xiàn)如下:



          # 定義一個包含 1-10 的 list
          list_a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
          # 實現(xiàn)列表表達(dá)式,用新的 list 接收下,看的明確一些
          list_b = [i*i for i in list_a]
          print(list_b)


          d7577d59d81070216b441ac81c8035b6.webp


          實際上,說起列表推導(dǎo)式,此處介紹的也只能是 Python 實現(xiàn)的語法而已,Python 解釋器看到此寫法的語法,會將其進(jìn)行相應(yīng)的語法解析。解釋一下,上述代碼中的列表推導(dǎo)式寫法。


          既然叫列表推導(dǎo)式,所以 list_b 的定義使用定義 list 的 [] 進(jìn)行定義。在 [] 中的內(nèi)容,可以使用表達(dá)式來書寫,依然使用 for 進(jìn)行對原列表遍歷,與普通的 for 循環(huán)不同的是,簡單計算邏輯,可以直接使用遍歷出來的變量放在 for 關(guān)鍵詞的前面進(jìn)行邏輯處理。


          [i*i for i in list_a]????# 列表推導(dǎo)式


          如果說列表推導(dǎo)式中書寫的是簡單的表達(dá)式,那么自然也可以進(jìn)行一些邏輯判斷。


          假設(shè)只想讓原列表中的偶數(shù)進(jìn)行平方計算的邏輯,可以修改代碼如下:


          # 定義一個包含 1-10 的 list
          list_a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
          # 實現(xiàn)列表表達(dá)式,用新的 list 接收下,看的明確一些
          list_b = [i * i for i in list_a if i % 2 == 0]
          print(list_b)


          b758d2d26a2d916364a12536b4456100.webp


          語法上來講只需繼續(xù)在 for 循環(huán)后面加上判斷邏輯即可。


          4

          集合推導(dǎo)式


          集合推導(dǎo)式,與列表推導(dǎo)式類似,既然叫集合推導(dǎo)式,那么最終要的結(jié)果必然是以集合形式的語法寫出來的,所以只需要將我們上面推導(dǎo)式地方的代碼,由 list 改為 set 即可。


          # 定義一個包含 1-10 的 list
          list_a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
          # 實現(xiàn)集合表達(dá)式,用新的變量接收下,看的明確一些
          b = {i * i for i in list_a if i % 2 == 0}
          print(type(b))
          print(b)


          37c6e92ee943320020d2ef9597170ed4.webp


          集合推導(dǎo)式,修改了定義集合語法的位置,使用 {} 定義,打印結(jié)果變成了 set 。類型也是 set。


          5

          字典推導(dǎo)式


          字典推導(dǎo)式與前面介紹的兩種有些區(qū)別,因為字典是兩個值,key 與 value,所以在寫法上,不能僅僅改變定義,還需借助字典本身的方法才能實現(xiàn)字典推導(dǎo)式,先看錯誤的寫法,如下:


          302595d72e41389e69bdda14634805c5.webp

          執(zhí)行一下,提示錯誤,解包的時候有太多值了。


          正確的寫法:


          # 定義一個字典變量gok(Glory of Kings,王者榮耀的意思)
          dict_gok = {
          'name': '小妲己',
          'age': '18',
          'gender': '女'
          }

          dict_b = {key: vaule for key, vaule in dict_gok.items()}
          print(dict_b)


          446811b78fa1786b0c1e2537d2fc6c8e.webp


          正確的寫法是字典調(diào)用 items方法,將 key - value 取出使用。


          小技巧,通過取出時交換 key - value 位置,得到的字典值也相反:


          6a2ba683fdf7e82feef17328bb253b24.webp


          6

          生成器generator


          你一定會奇怪,為什么沒有元組推導(dǎo)式?那么我們來試試,若按照上面的邏輯來一次元組推導(dǎo)式的寫法會怎么樣呢?


          # 定義一個包含 1-10 的 list
          list_a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
          # 實現(xiàn)集合表達(dá)式,用新的變量接收下,看的明確一些
          b = (i * i for i in list_a if i % 2 == 0)
          print(type(b))
          print(b)


          627d7b4ceee6c5a916debea935ab89b8.webp


          可以發(fā)現(xiàn),使用“元組定義推導(dǎo)式,生成出來的是一個 generator 的類型。對于 generator 的使用方法有兩種,一種是直接調(diào)用 next 方法,還有一種通過 for 循環(huán)遍歷使用,推薦使用 for 循環(huán)。


          4954c4931f567a9f134428b5539c7b39.webp


          此種方式調(diào)用非得累死,generator 保存的是算法,每次調(diào)用 next ,就計算出下一個元素的值,直到計算到最后一個元素,沒有更多的元素時,還會主動拋出 StopIteration 的錯誤。


          9798b8969a6f48b66a0bbc36026d2d34.webp


          所以說,還是 for 循環(huán)最省事:


          9e5acbfb5e46efed8695a430611fd1d7.webp


          7

          生成器的優(yōu)點


          通過列表生成式,我們可以直接創(chuàng)建一個列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費了。所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。在Python中,這種一邊循環(huán)一邊計算的機(jī)制,稱為生成器:generator。

          廖雪峰的官方網(wǎng)站 - 生成器


          在廖雪峰老師官方網(wǎng)站(自行百度查看即可) - 生成器的定義處,其實就很清楚的說明了生成器與列表推導(dǎo)式最大的區(qū)別,這里筆者直接引用過來了,而生成器最大的優(yōu)點就是節(jié)省內(nèi)存,不會因為數(shù)據(jù)龐大而導(dǎo)致內(nèi)存溢出。


          當(dāng)然說到生成器,并不僅僅有上面的寫法可以寫出生成器。在函數(shù)中,通過 yield 關(guān)鍵字來代替 return 關(guān)鍵詞,也可以生成對應(yīng)的 generator 生成器。


          def test():
          for i in range(5):
          print('before yield i')
          yield i
          print('after yield i')

          a = test()
          print(type(a))
          for i in a:
          print(i)


          e1b6ac22f70694a321e48bdb731822b4.webp


          與return不同,雖然 yield 會將當(dāng)前值先返回調(diào)用處,但依然會執(zhí)行 yield 后的邏輯,可以看到上面的案例中,返回了 i 后,依然打印了“after yield i”。


          8

          總結(jié)


          列表生成器在編寫代碼時,用得好可以大大簡潔代碼,而生成器有助于大數(shù)據(jù)遍歷時的操作。


          筆者早期剛寫代碼時,就遇到了大數(shù)據(jù)讀取到內(nèi)存的問題,那時也是初學(xué) Python ,對于生成器的了解還不是那么深刻,所以沒有利用上,依然清晰地記著項目第一版的代碼,就是暴力的將 3~4 GB 文件內(nèi)容直接讀到內(nèi)存中,最后程序跑著跑著就內(nèi)存溢出了,直接導(dǎo)致程序自己死掉了。


          如果當(dāng)時利用好生成器,想必后來也不用那么麻煩的使用“分而治之”的思想去處理文件了。所以當(dāng)遇到大數(shù)據(jù)時,不妨利用生成器試試,尤其是 yield 關(guān)鍵詞,使用得當(dāng)會省去不少麻煩呢!


          至此完!


          23b84aeae4ebda1f496e6acee77e94c6.webp


          瀏覽 90
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  看操| 亚洲精品国产精品乱码不卡√香蕉 亚洲日韩一区二区三区四区丨高清 | 蜜桃久久午夜 | 五月情色天 | 欧日无码一区二区三区在线 |