<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 代碼不可不知的函數(shù)式編程技術(shù)

          共 7726字,需瀏覽 16分鐘

           ·

          2021-06-24 19:22

          點擊上方小白學視覺”,選擇加"星標"或“置頂

          重磅干貨,第一時間送達

          本文轉(zhuǎn)自|深度學習這件小事
          本文對 Python 中的函數(shù)式編程技術(shù)進行了簡單的入門介紹。
          近來,越來越多人使用函數(shù)式編程(functional programming)。因此,很多傳統(tǒng)的命令式語言(如 Java 和 Python)開始支持函數(shù)式編程技術(shù)。本文對 Python 中的函數(shù)式編程技術(shù)進行了簡單的入門介紹。

          本文適合對函數(shù)式編程有基本了解的讀者。如果你對函數(shù)式編程并不熟悉,可以先閱讀這篇文章:https://medium.com/@yannickdot/functional-programming-101-6bc132674ec5。

          本文作者是新加坡國立大學計算機學院和「USP」博學計劃學生 Raivat Shah,專注于編程與數(shù)據(jù)研究。

          頭等函數(shù)

          在 Python 中,函數(shù)是「頭等公民」(first-class)。也就是說,函數(shù)與其他數(shù)據(jù)類型(如 int)處于平等地位。

          因而,我們可以將函數(shù)賦值給變量,也可以將其作為參數(shù)傳入其他函數(shù),將它們存儲在其他數(shù)據(jù)結(jié)構(gòu)(如 dicts)中,并將它們作為其他函數(shù)的返回值。

          把函數(shù)作為對象

          由于其他數(shù)據(jù)類型(如 string、list 和 int)都是對象,那么函數(shù)也是 Python 中的對象。我們來看示例函數(shù) foo,它將自己的名稱打印出來:

          def foo():
             print("foo")

          由于函數(shù)是對象,因此我們可以將函數(shù) foo 賦值給任意變量,然后調(diào)用該變量。例如,我們可以將函數(shù)賦值給變量 bar:

          bar = foo
          bar()
          #will print "foo" to the console

          語句 bar = foo 將函數(shù) foo 引用的對象賦值給變量 bar。

          把對象作為函數(shù)

          當對象可調(diào)用時(callable),它們與函數(shù)一樣,如 object()。這是通過 __call__ 方法實現(xiàn)的。

          示例如下:

          class Greeter:
             def __init__(self, greeting):
                self.greeting = greeting
             def __call__(self, name):
                return self.greeting + " " + name

          每一次配置 Greeter 類的對象時,我們都會創(chuàng)建一個新的對象,即打招呼時可以喊的新名字。如下所示:

          morning = Greeter("good morning"#creates the callable object
          morning("john"# calling the object
          #prints "good morning john" to the console

          我們可以調(diào)用 morning 對象的原因在于,我們已經(jīng)在類定義中使用了 __call__ 方法。為了檢查對象是否可調(diào)用,我們使用內(nèi)置函數(shù) callable:

          callable(morning) #true
          callable(145) #falseint is not callable. 

          數(shù)據(jù)結(jié)構(gòu)內(nèi)的函數(shù)

          函數(shù)和其他對象一樣,可以存儲在數(shù)據(jù)結(jié)構(gòu)內(nèi)部。例如,我們可以創(chuàng)建 int to func 的字典。當 int 是待執(zhí)行步驟的簡寫時,這就會派上用場。

          # store in dictionary
          mapping = {
             0 : foo,
             1 : bar
          }
          x = input() #get integer value from user
          mapping[x]() #call the func returned by dictionary access

          類似地,函數(shù)也可以存儲在多種其他數(shù)據(jù)結(jié)構(gòu)中。

          把函數(shù)作為參數(shù)和返回值

          函數(shù)還可以作為其他函數(shù)的參數(shù)和返回值。接受函數(shù)作為輸入或返回函數(shù)的函數(shù)叫做高階函數(shù),它是函數(shù)式編程的重要組成部分。

          高階函數(shù)具備強大的能力。就像《Eloquent JavaScript》中解釋的那樣:

          「高階函數(shù)允許我們對動作執(zhí)行抽象,而不只是抽象數(shù)值?!?/span>

          我們來看一個例子。假設我們想對一個項目列表(list of items)執(zhí)行迭代,并將其順序打印出來。我們可以輕松構(gòu)建一個 iterate 函數(shù):

          def iterate(list_of_items):
              for item in list_of_items:
                  print(item)
          看起來很酷吧,但這只不過是一級抽象而已。如果我們想在對列表執(zhí)行迭代時進行打印以外的其他操作要怎么做呢?
          這就是高階函數(shù)存在的意義。我們可以創(chuàng)建函數(shù) iterate_custom,待執(zhí)行迭代的列表和要對每個項應用的函數(shù)都是 iterate_custom 函數(shù)的輸入:

          def iterate_custom(list_of_items, custom_func):
             for item in list_of_items:
                  custom_func(item)

          這看起來微不足道,但其實非常強大。

          我們已經(jīng)把抽象的級別提高了一層,使代碼具備更強的可重用性。現(xiàn)在,我們不僅可以在打印列表時調(diào)用該函數(shù),還可以對涉及序列迭代的列表執(zhí)行任意操作。

          函數(shù)還能被返回,從而使事情變得更加簡單。就像我們在 dict 中存儲函數(shù)一樣,我們還可以將函數(shù)作為控制語句,來決定適合的函數(shù)。例如:

          def add(x, y):
              return x + y
          def sub(x, y):
              return x - y
          def mult(x, y):
              return x * y
          def calculator(opcode):
              if opcode == 1:
                 return add
              elif opcode == 2:
                 return sub
              else:
                 return mult 
          my_calc = calculator(2#my calc is a subtractor
          my_calc(54#returns 5 - 4 = 1 
          my_calc = calculator(9#my calc is now a multiplier
          my_calc(54#returns 5 x 4 = 20. 
          嵌套函數(shù)
          函數(shù)還可以在其他函數(shù)內(nèi)部,這就是「內(nèi)部函數(shù)」。內(nèi)部函數(shù)在創(chuàng)建輔助函數(shù)時非常有用,輔助函數(shù)即作為子模塊來支持主函數(shù)的小型可重用函數(shù)。

          在問題需要特定函數(shù)定義(參數(shù)類型或順序)時,我們可以使用輔助函數(shù)。這種不遵循傳統(tǒng)做法的操作使得解決問題變得更加簡單,示例參見:http://www-inst.eecs.berkeley.edu/~cs61a/sp12/lectures/lect4-2x3.pdf。

          假設你想定義一個斐波那契函數(shù) fib(n),該函數(shù)只有一個參數(shù) n,我們必須返回第 n 個斐波那契數(shù)。

          定義此類函數(shù)的一種可行方式是:使用輔助函數(shù)來追蹤斐波那契數(shù)列的前兩個項(因為斐波那契數(shù)是前兩個數(shù)之和)。

          def fib(n):
              def fib_helper(fk1, fk, k):
                  if n == k:
                     return fk
                  else:
                     return fib_helper(fk, fk1+fk, k+1)
              if n <= 1:
                 return n
              else:
                 return fib_helper(011)
          將該計算從函數(shù)主體移到函數(shù)參數(shù),這具備非常強大的力量。因為它減少了遞歸方法中可能出現(xiàn)的冗余計算。

          單表達式函數(shù)(Lambda 表達式)

          如果我們想在未給函數(shù)命名之前寫一個函數(shù)要怎么做?如果我們想寫一個簡短的單行函數(shù)(如上述示例中的函數(shù) foo 或 mult)要怎么做?

          我們可以在 Python 中使用 lambda 關(guān)鍵字來定義此類函數(shù)。示例如下:

          mult = lambda x, y: x * y
          mult(1, 2) #returns 2
          該 mult 函數(shù)的行為與使用傳統(tǒng) def 關(guān)鍵字定義函數(shù)的行為相同。
          注意:lambda 函數(shù)必須為單行,且不能包含程序員寫的返回語句。

          事實上,它們通常具備隱式的返回語句(在上面的示例中,函數(shù)想表達 return x * y,不過我們省略了 lambda 函數(shù)中的顯式返回語句)。

          lambda 函數(shù)更加強大和精準,因為我們還可以構(gòu)建匿名函數(shù)(即沒有名稱的函數(shù)):

          (lambda x, y: x * y)(910#returns 90

          當我們只需要一次性使用某函數(shù)時,這種方法非常方便。例如,當我們想填充字典時:

          import collections
          pre_fill = collections.defaultdict(lambda: (0, 0))
          #all dictionary keys and values are set to 0

          接下來我們來看 Map、Filter 和 Reduce,以更多地了解 lambda。


          Map、Filter 和 Reduce

          Map

          map 函數(shù)基于指定過程(函數(shù))將輸入集轉(zhuǎn)換為另一個集合。這類似于上文提到的 iterate_custom 函數(shù)。例如:

          def multiply_by_four(x):
              return x * 4
          scores = [3, 6, 8, 3, 5, 7]
          modified_scores = list(map(multiply_by_four, scores))
          #modified scores is now [12, 24, 32, 12, 20, 28]
          在 Python 3 中,map 函數(shù)返回的 map 對象可被類型轉(zhuǎn)換為 list,以方便使用。現(xiàn)在,我們無需顯式地定義 multiply_by_four 函數(shù),而是定義 lambda 表達式:
          modified_scores = list(map(lambda x: 4 * x, scores))

          當我們想對集合內(nèi)的所有值執(zhí)行某項操作時,map 函數(shù)很有用。

          Filter

          就像名稱所顯示的那樣,filter 函數(shù)可以幫助篩除不想要的項。例如,我們想要去除 scores 中的奇數(shù),那么我們可以使用 filter:

          even_scores = list(filter(lambda x: True if (x % 2 == 0else False, scores))
          #even_scores = [6, 8]

          由于提供給 filter 的函數(shù)是逐個決定是否接受每一個項的,因此該函數(shù)必須返回 bool 值,且該函數(shù)必須是一元函數(shù)(即只使用一個輸入?yún)?shù))。

          Reduce

          reduce 函數(shù)用于「總結(jié)」或「概述」數(shù)據(jù)集。例如,如果我們想要計算所有分數(shù)的總和,就可以使用 reduce:

          sum_scores = reduce((lambda x, y: x + y), scores)
          #sum_scores = 32

          這要比寫循環(huán)語句簡單多了。注意:提供給 reduce 的函數(shù)需要兩個參數(shù):一個表示正在接受檢查的項,另一個表示所用運算的累積結(jié)果。

          本文是關(guān)于函數(shù)式編程的一篇入門文章,雖然盡量完備地介紹了相關(guān)的知識,但并不是那么深入。如想了解更多,大家可以閱讀以下資源:

          • Best Practices for Using Functional Programming in Python:https://kite.com/blog/python/functional-programming/

          • Functional Programming Tutorials and Notes:https://www.hackerearth.com/zh/practice/python/functional-programming/functional-programming-1/tutorial/


          原文鏈接:https://medium.com/better-programming/introduction-to-functional-programming-in-python-3d26cd9cbfd7


          下載1:OpenCV-Contrib擴展模塊中文版教程
          在「小白學視覺」公眾號后臺回復:擴展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM算法、立體視覺、目標跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺實戰(zhàn)項目52講
          小白學視覺公眾號后臺回復:Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學校計算機視覺。

          下載3:OpenCV實戰(zhàn)項目20講
          小白學視覺公眾號后臺回復:OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學習進階。

          交流群


          歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~


          瀏覽 35
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  免费18禁 | 无码人妻一区二区三区蜜桃视频 | 国产精品99久久久久久噜噜 | 福利色在线播放 | 国产综合久久7777777 |