高階函數與函數式編程

2021-02-14 小菜學編程

從前面章節,我們知道 Python 函數是以對象的形式實現的,屬於 一等對象 ( first-class object )。根據程式語言理論,一等對象必須滿足以下條件:

Python 函數同時滿足這幾個條件,因而也被稱為 一等函數高階函數 則是指那些以函數為參數,或者將函數作為結果返回的函數。對高階函數稍加利用,便能玩出很多花樣來。本節從一些典型的案例入手,講解 Python 函數高級用法。合理應用函數式編程技巧,不僅能讓代碼更加簡潔優雅,還能提高開發效率和程序質量。

函數式編程技巧最適合用在數據處理場景,接下來以成績單計算為例,展開講解。原始數據如下:

scores = [
    {
        'name': '小雪',
        'chinese': 90,
        'math': 75,
        'english': 85,
    },
    {
        'name': '小明',
        'chinese': 70,
        'math': 95,
        'english': 80,
    },
    {
        'name': '小麗',
        'chinese': 85,
        'math': 85,
        'english': 90,
    },
    {
        'name': '小宇',
        'chinese': 85,
        'math': 95,
        'english': 90,
    },
    {
        'name': '小剛',
        'chinese': 65,
        'math': 70,
        'english': 55,
    },
    {
        'name': '小新',
        'chinese': 85,
        'math': 85,
        'english': 80,
    },
]

sorted

排序是我們再熟悉不過的場景,如果待排序元素可以直接比較,調用 sorted 函數即可:

>>> numbers = [2, 8, 6, 9, 7, 0, 1, 7, 0, 3]
>>> sorted(numbers)
[0, 0, 1, 2, 3, 6, 7, 7, 8, 9]

對比較複雜的數據進行排序,則需要一些額外的工作。假如語文老師想對語文成績進行排序,改如何進行呢?

sorted 支持指定一個自定義排序函數 key ,該函數以列表元素為參數,返回一個值決定該元素的次序。由於我們需要根據語文成績對元素進行排序,因此需要實現一個函數將語文成績提取出來作為比較基準:

def by_chinese(item):
    return item['chinese']

現在只需要將 by_chinese 函數作為 key 參數傳給 sorted 即可實現語文成績排序:

>>> for item in sorted(scores, key=by_chinese):
...     print(item['name'], item['chinese'])
...
小剛 65
小明 70
小麗 85
小宇 85
小新 85
小雪 90

自定義排序函數還可以控制升降序,如果需要按分數從高到底依次排序,可以返回成績的負數作為排序基準:

def by_chinese_desc(item):
    return -item['chinese']

>>> for item in sorted(scores, key=by_chinese_desc):
...     print(item['name'], item['chinese'])
...
小雪 90
小麗 85
小宇 85
小新 85
小明 70
小剛 65

當然了,通過 sorted 函數 reverse 參數控制升降序,是一個更好的編程習慣,邏輯更清晰:

>>> for item in sorted(scores, key=by_chinese, reverse=True):
...     print(item['name'], item['chinese'])
...
小雪 90
小麗 85
小宇 85
小新 85
小明 70
小剛 65

lambda

像 by_chinese 這樣直接返回結果的極簡函數,其實沒有必要大動幹戈,用 匿名函數 定義即可。Python 中的 lambda 關鍵字用於定義匿名函數,匿名函數只需給出參數列表以及一個表達式作為函數返回值:

這樣一來,by_chinese 這個自定義排序函數,可以這樣來定義:

by_chinese = lambda item: item['chinese']

相應地,我們實現語文成績排序的代碼編程這樣子:

>>> for item in sorted(scores, key=lambda item: item['chinese']):
...     print(item['name'], item['chinese'])
...
小剛 65
小明 70
小麗 85
小宇 85
小新 85
小雪 90

數學老師來了,也只需要改動一點點,就能實現數學成績排序了:

>>> for item in sorted(scores, key=lambda item: item['math']):
...     print(item['name'], item['math'])
...
小剛 70
小雪 75
小麗 85
小新 85
小明 95
小宇 95

函數式程式語言一般都會提供 map 、 filter 以及 reduce 這 3 個高階函數,再複雜的數據統計處理任務都可以轉換成這些算子的組合。因此,不少大數據平臺,例如 Hadoop 等,都以 map 、 reduce 為基礎算子。

Python 內部也自帶了這幾個高階函數,那麼這幾個高階函數如何與基礎算子組合,才能迸發巨大威力呢?點擊「閱讀原文」,獲取更多詳情!

相關焦點

  • Kotlin函數式編程
    那麼在函數式編程中當然一切皆是函數。在Kotlin中函數式的地位和對象一樣高,你可以在方法中輸入函數,也可以返回函數。函數式編程FP特徵:函數式編程核心概念:函數是「一等公民」:是指函數與其他數據類型是一樣的,處於平等地位。函數可以作為其他函數的參數傳入,也可以作為其他函數的返回值返回。
  • 函數式編程聖經
    上帝看到約翰·麥卡錫發明了表處理語言 Lisp,卻只用來學術研究,很是傷心,就把 Lisp 解釋器的秘密告訴了他的學生史蒂芬·羅素,史蒂芬·羅素將eval函數在IBM 704機器上實現後,函數式編程的大門第一次向人類打開了。
  • Golang 函數式編程簡述
    什麼是 Functional Programming 首先我們需要研究一下什麼是高階函數編程?所謂的 Functional Programming,一般被譯作函數式編程(以 λ演算 為根基)。函數式編程,是指忽略(通常是不允許)可變數據(以避免它處可改變的數據引發的邊際效應),忽略程序執行狀態(不允許隱式的、隱藏的、不可見的狀態),通過函數作為入參,函數作為返回值的方式進行計算,通過不斷的推進(迭代、遞歸)這種計算,從而從輸入得到輸出的編程範式。在函數式編程範式中,沒有過程式編程所常見的概念:語句,過程控制(條件,循環等等)。
  • Python中的函數式編程
    (英語:functional programming)或稱函數程序設計,又稱泛函編程,是一種編程範型,它將電腦運算視為數學上的函數計算,並且避免使用程序狀態以及易變對象。(維基百科:函數式編程)所謂編程範式(Programming paradigm)是指編程風格、方法或模式,比如面向過程編程(C語言)、面向對象編程(C++)、面向函數式編程(Haskell),並不是說某種程式語言一定屬於某種範式,例如 Python 就是多範式程式語言。
  • 現代C++函數式編程
    ,展示了現代C++實現函數式編程的方法和技巧,同時也體現了現代C++的強大威力和無限可能。函數式編程是一種編程範式,它有下面的一些特徵:函數是一等公民,可以像數據一樣傳來傳去高階函數遞歸pipeline惰性求值柯裡化偏應用函數C++98/03中的函數對象,和C++11中的Lambda表達式、std::function和std::bind讓C++的函數式編程變得容易
  • [翻譯]淺談JavaScript中的高階函數
    高階函數的採用使得JavaScript適合用來做函數式編程。在JavaScript中,高階函數的使用隨處可見。如果你已經用JavaScript寫過一陣子的代碼,那麼你可能已經在不知情的情況下使用過它了。為了完全理解這個概念,你首先要了解什麼是函數式編程以及頭等函數的概念。
  • 函數式編程
    ,我們會看到如下函數式編程的長相:函數式編程的三大特性:immutable data 不可變數據:像Clojure一樣,默認上變量是不可變的,如果你要改變變量,你需要把變量copy出去修改。函數式編程的幾個技術map & reduce :這個技術不用多說了,函數式編程最常見的技術就是對一個集合做Map和Reduce操作。這比起過程式的語言來說,在代碼上要更容易閱讀。
  • 大數據入門:Scala函數式編程
    提到Scala,首先會提到的一個概念,就是函數式編程,這也是Scala語言區別與其他程式語言的典型特徵。Scala是一門多範式(multi-paradigm)的程式語言,設計初衷是要集成面向對象編程和函數式編程的各種特性。
  • 函數式編程,真香
    最開始接觸函數式編程的時候是在小米工作的時候,那個時候看老大以前寫的代碼各種 compose,然後一些 ramda 的一些工具函數,看著很吃力,然後極力吐槽函數式編程,現在回想起來,那個時候的自己真的是見識短淺,只想說,'真香'。
  • 一文帶你了解什麼是JavaScript 函數式編程?
    函數式編程在前端已經成為了一個非常熱門的話題。在最近幾年裡,我們看到非常多的應用程式代碼庫裡大量使用著函數式編程思想。本文將略去那些晦澀難懂的概念介紹,重點展示在 JavaScript 中到底什麼是函數式的代碼、聲明式與命令式代碼的區別、以及常見的函數式模型都有哪些?
  • 寫Python 代碼不可不知的函數式編程技術
    近來,越來越多人使用函數式編程(functional programming)。因此,很多傳統的命令式語言(如 Java 和 Python)開始支持函數式編程技術。本文對 Python 中的函數式編程技術進行了簡單的入門介紹。本文適合對函數式編程有基本了解的讀者。
  • python高階函數:map、filter、reduce的替代品
    什麼是高階函數?高階函數是一種將函數作為參數,或者把函數作為結果返回的函數,map函數、sorted函數就是高階函數的典型例子。map函數在小編以前的文章中做過相應的知識分享。sorted函數是python的內置函數,它的可選參數key用於提供一個函數,它可以將函數應用到各個元素上進行排序。
  • 【第1679其】函數式編程淺析
    類似詩詞中的語碼那樣,我們需要熟悉函數式編程中的一些概念,才能更好的理解函數式語句。在 JS 中,return 返回的值也可以是一個函數,這其實是我們熟悉的高階函數。實際上高階函數可能算是函數式編程的基石之一了,函數式編程從某種意義上講就是在不斷的創建各種高階函數。the shape of function輸入輸出的個數,決定了函數的「形狀」(shape)。
  • 寫 Python 代碼不可不知的函數式編程技術
    作者:Raivat Shah參與:魔王、Jamin本文對 Python 中的函數式編程技術進行了簡單的入門介紹。近來,越來越多人使用函數式編程(functional programming)。因此,很多傳統的命令式語言(如 Java 和 Python)開始支持函數式編程技術。
  • 10分鐘學會python函數式編程
    一旦你設置了一個變量,它就永遠保持這種狀態(注意,在純函數式語言中,它們不是變量)。因此,函數式編程沒有副作用。副作用指的是函數改變它自己以外的東西。讓我們看一些典型Python代碼的示例:開頭我說過純函數式程式語言沒有變量。更高階的函數使這變得更容易。Python中的所有函數都是一等公民。
  • 使用JavaScript對象數組進行函數式編程
    通過這些例子,我們將學習這些方法的強大程度,同時了解它們與函數式編程的關係。功能編程:好的部分函數式編程有許多概念超出了我們要實現的範圍。在本文中,我們將討論一些絕對的基礎知識。在整個示例中,我們將傾向於使用多個語句的單個表達式。
  • Java如何支持函數式編程?
    Java 8開始,引入了函數式編程接口與Lambda表達式,便於開發者寫出更少更優雅的代碼。什麼是函數式編程?函數式編程的特點是什麼?本文通過代碼實例,從Stream類、Lambda表達式和函數接口這三個語法概念來分享Java對函數式編程的支持。文末福利:Java微服務沙箱體驗挑戰。
  • 【瞎讀001】Why Functional Programming Matters <為什麼函數式編程很重要>【上】
    由於是模塊化是成功編程的關鍵,因此函數式語言對現實世界至關重要。1 Introduction      主要是講了函數式編程很牛逼啦,有哪些特徵和優點啦布拉布拉的,來證明這玩意兒是真的對現實世界至關重要。
  • Facebook 開源 Skip,面向對象+函數式程式語言
    而通過靜態類型系統追蹤可變性,Skip 完成了這個目標,同時它也支持現代程式語言特徵,例如 trait、泛型與子類型。Skip 是一種通用程式語言,它跟蹤副作用,提供反應失效的緩存、ergonomics 和安全的並行化以及高效的 GC。Skip 是靜態類型的,它使用 LLVM 提前編譯,生成高度優化的可執行文件。
  • 白話 Python 的函數式編程
    今天和大家聊聊 Python 的函數式編程特性。