<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 之父為什么嫌棄 lambda 匿名函數(shù)?

          共 4630字,需瀏覽 10分鐘

           ·

          2021-04-29 19:46

          點擊上方“Python爬蟲與數(shù)據(jù)挖掘”,進行關注

          回復“書籍”即可獲贈Python從入門到進階共10本電子書

          乘興南游不戒嚴,九重誰省諫書函。

          Python 支持 lambda 匿名函數(shù),其擴展的 BNF 表示法是lambda_expr ::= "lambda" [parameter_list] ":" expression,也就是lambda 參數(shù)序列:表達式

          這是一種便捷的函數(shù)定義方式,若翻譯成我們熟知的函數(shù)形式,會是這個樣子:

          def <lambda>(parameter_list):
              return expression

          也就是說,Python 中的 lambda 函數(shù)是一種可接收多個參數(shù)的函數(shù),返回值是一個表達式。

          它最大的好處是單行簡潔,不需要函數(shù)命名與換行縮進。

          不得不說,匿名函數(shù)有時候是挺好用的,比如下文會介紹到的一些常見用法,它因此受到了不少人的推崇。

          但是,匿名函數(shù)通常也會造成代碼難以閱讀,容易被人濫用,再加上 Python 只提供了對它的“殘疾的”支持,所以又有一些觀點不建議使用匿名函數(shù)。

          事實上,Python 之父 Guido van Rossum 就屬于“不推薦使用派”,他甚至曾經(jīng)(2005年)想要移除 lambda,只不過最后妥協(xié)了。

          出處:https://www.artima.com/weblogs/viewpost.jsp?thread=98196

          lambda 這一個由其他開發(fā)者貢獻進來的特性(借鑒自 lisp 語言),存在了十多年,但是卻被這門語言的創(chuàng)造者(兼首席設計師)所嫌棄,最后竟然還奇跡般地幸存了下來,對于這個故事,大家是否覺得挺有戲劇性的?

          接下來,本文就仔細聊一聊這個處境尷尬卻生命力頑強的 lambda 匿名函數(shù)吧!

          1、lambda 怎么使用?

          lambda 函數(shù)通常的用法是結合 map()、reduce()、filter()、sorted() 等函數(shù)一起使用,這些函數(shù)的共性是:都可以接收其它函數(shù)作為參數(shù)。

          例如下面的幾個例子:

          my_list = [315410]

          # 元素全加1,結果:[4, 2, 6, 5, 11]
          list(map(lambda i:i+1, my_list)) 

          # 過濾小于10的元素,結果:[3, 1, 5, 4]
          list(filter(lambda i:i<10, my_list)) 

          # 元素累加,結果:33
          from functools import reduce
          reduce(lambda i,j:i+j, my_list, 10)

          # 字典按值排序,結果:[('b', 1), ('a', 3), ('d', 4), ('c', 5)]
          my_dict = {'a':3'b':1'c':5'd':4}
          sorted(my_dict.items(), key=lambda item:item[1])

          初學者也許會覺得代碼讀不懂,但是只要記住“Python中的函數(shù)是一等公民”,知道一個函數(shù)可以被作為另一個函數(shù)的參數(shù)或者返回值,就容易理解了。

          比如對于 map() 函數(shù)的例子,你可以理解成這個形式:

          my_func = lambda i:i+1
          list(map(my_func, my_list)) 

          甚至可以還原成普通的函數(shù):

          def add_one(i):
              return i+1

          list(map(add_one, my_list)) 

          map() 函數(shù)的第一個參數(shù)是一個函數(shù),第二個參數(shù)是一個可迭代對象。這第一個參數(shù)會迭代地調用第二個參數(shù)中的元素,調用的結果以迭代器的形式返回。

          這個例子使用了 list(),是為了方便一次性取出迭代器中的元素,直觀地展示出來,在實際使用中,很可能會是基于迭代器的形式。

          由這幾種用法,我們可以總結出 lambda 函數(shù)的使用規(guī)律:
          • 它出現(xiàn)在需要使用函數(shù)的地方
          • 它適合實現(xiàn)簡單的功能
          • 它是一次性的用途,不能在其它地方復用
          • 它一般不會被獨立使用,總是作為其它函數(shù)的一部分

          2、lambda 有什么問題?

          由上面的用法可以看出,使用 lambda 函數(shù)的代碼比較緊湊簡潔,所以有人稱它體現(xiàn)了“Pythonic”的優(yōu)雅思想。

          但是,lambda 函數(shù)有沒有什么缺陷呢?

          有!當前的 lambda 函數(shù)有一個最大的問題,即只支持單行表達式,無法實現(xiàn)豐富的功能,例如無法在函數(shù)創(chuàng)建時使用語句(statement),無法使用 if-else 的判斷條件,也無法使用 try-except 的異常捕獲機制,等等。

          這極大地限制了它的能力,導致了它被人詬病為“殘疾的”。

          從技術實現(xiàn)的角度上看, 這個問題可以通過語法層面的設計來解決。

          在當年的郵件組討論中,有人提出過一些解決思路,比如這封郵件:

          出處:https://mail.python.org/pipermail/python-dev/2006-February/060654.html

          它提出了一個lambda args::suite 的想法,支持寫成這樣的形式:

          ss = sorted(seq, key=(lambda x::
                      tryreturn abs(x)
                      except TypeError: return 0))

          但是,Guido 很快就否決了這個思路。

          他寫了一篇文章《Language Design Is Not Just Solving Puzzles》來回應:

          出處:https://www.artima.com/weblogs/viewpost.jsp?thread=147358

          其基本觀點是:不能光顧著解決一個問題/實現(xiàn)某種功能,就引入缺乏“Pythonicity”的語言設計。

          那么,為什么 Guido 會認為這是一種不好的設計呢?

          我試著概括一下,理由是:
          • 雙冒號“::”憑空在此引入,但是跟切片語法中的“::”完全不同,而且跟 C++/Perl 中的作用域操作符用法也不同

          • 即使不用雙冒號,用其它符號表示(比如單冒號),還是難以接受,因為都會在一個表達式中嵌入縮進代碼塊。這就跟使用花括號和 begin/end 關鍵字來作語句分組(statement grouping)一樣,都令人難以接受

          • 在 lambda 中實現(xiàn)其它功能并不重要,這還會讓解析器變得復雜(需區(qū)分是否有縮進、記錄縮進級別),顯得小題大做了

          簡而言之,他認為簡潔友好的用戶體驗更為重要,如果簡潔的語法無法滿足需求,就應該寫成具名函數(shù)的形式,而非設計出復雜的匿名函數(shù)。

          3、為什么 Guido 想移除 lambda?

          上文提到的多行 lambda 語句(multi-statement lambda)事件發(fā)生在 2006 年,我們看到了 Guido 不想給 lambda 引入復雜設計的原因。

          但是,早在 2005 年,Guido 就曾經(jīng)想要從 Python 移除 lambda,他對它的“嫌棄”是一個“歷史悠久”的傳統(tǒng)……

          在《The fate of reduce() in Python 3000》這篇短文中,Guido 提出要一次性移除 reduce()、map()、filter() 以及 lambda。

          移除 lambda 的理由如下:
          • 對于不熟悉 Lisp 或 Scheme 的用戶,lambda 這名字容易造成混淆

          • 很多人誤以為匿名函數(shù)能做嵌套函數(shù)不能做的事,但其實并無區(qū)別;存在lambda,就會造成不必要的選擇,減少選擇,可以簡化思維

          • 移除 reduce()、map() 和 filter() 后,就沒必要寫簡短的局部函數(shù)了

          回顧一下我們在前文中總結出的 lambda 的 4 條使用規(guī)律,可以發(fā)現(xiàn)它跟幾個高階函數(shù)(可以接收其它函數(shù)作為參數(shù)的函數(shù))有較強的“寄生關系”,如果它們能移除了的話,lambda 確實就沒有什么獨立存留的意義了。

          那么,為什么 Guido 覺得應該移除那幾個高階函數(shù)呢?

          主要的理由有:
          • 可以替換成更加清晰的列表解析式或者生成器表達式,例如 filter(P,S) 可以寫成 [x for x in S if P(x)],map(F, S) 寫成 [F(x) for x in S]

          • 至于 reduce(),他說這是最討厭的,除了涉及 + 和 * 的少數(shù)用法,其它時候他總要拿出紙筆來畫圖解才能搞清楚。除了顯式地寫循環(huán),他還針對 reduce() 的幾種用法而提出了幾個替代用法,包括引入新的 any() 和 all() 函數(shù)

          總體而言,Guido 的想法暗合了《The Zen of Python》中的這一條:There should be one-- and preferably only one --obvious way to do it。

          但是回到現(xiàn)實,為了照顧某些人的習慣,以及對兼容性的考慮,Guido 最后保守地放棄了“清理異端”的計劃。

          因此,lambda 得以從 Python 最高獨裁者的手上死里逃生。直到一年后,它試圖興風作浪(多行表達式),卻慘遭鎮(zhèn)壓。

          我仿佛聽到了 Guido 的內(nèi)心 OS:當初我想刪除東西的時候,你們百般阻撓,現(xiàn)在你們想添加東西,哼,沒門!……

          哈哈,開了個玩笑。

          Guido 的所有決定都體現(xiàn)了他的 Pythonic 設計美學、自恰的邏輯一致性以及對社區(qū)聲音的權衡。

          對于 lambda,我認可他的觀點,而通過回溯語法發(fā)展的歷史,我覺得自己對于 Python 的理解變得更為豐富了。不知道你可有同感?

          ------------------- End -------------------

          往期精彩文章推薦:

          歡迎大家點贊,留言,轉發(fā),轉載,感謝大家的相伴與支持

          想加入Python學習群請在后臺回復【入群

          萬水千山總是情,點個【在看】行不行

          /今日留言主題/

          隨便說一兩句吧~~

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲AV片不卡无码久久蜜芽 | 一级黄色电影免费在线 | 韩国精品在线播放 | 大香蕉手机视频 | 偷拍亚洲天堂 |