欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python函數(shù)式編程:從入門到走火入魔

系統(tǒng) 1761 0

附Java/C/C++/機器學習/算法與數(shù)據(jù)結構/前端/安卓/Python/程序員必讀書籍書單大全:

書單導航頁(點擊 右側 極客俠棧 即可打開個人博客): 極客俠棧
①【Java】學習之路吐血整理技術書從入門到進階最全50+本(珍藏版)
②【算法數(shù)據(jù)結構+acm】從入門到進階吐血整理書單50+本(珍藏版)
③【數(shù)據(jù)庫】從入門到進階必讀18本技術書籍網(wǎng)盤吐血整理網(wǎng)盤(珍藏版)
④【W(wǎng)eb前端】從HTML到JS到AJAX到HTTP從框架到全棧幫你走更少彎路(珍藏版)? ?
⑤【python】書最全已整理好(從入門到進階)(珍藏版)

⑥【機器學習】+python整理技術書(從入門到進階已經(jīng)整理好)(珍藏版)
⑦【C語言】推薦書籍從入門到進階帶你走上大牛之路(珍藏版)
⑧【安卓】入門到進階推薦書籍整理pdf書單整理(珍藏版)

⑨【架構師】之路史詩級必讀書單吐血整理四個維度系列80+本書(珍藏版)

⑩【C++】吐血整理推薦書單從入門到進階成神之路100+本(珍藏)

? 【ios】IOS書單從入門到進階吐血整理(珍藏版)

-------------------------------------------------------------------------------------------------------------------------------------------

函數(shù)式編程源自于數(shù)學理論,它似乎也更適用于數(shù)學計算相關的場景,因此本文以一個簡單的數(shù)據(jù)處理問題為例,逐步介紹 Python 函數(shù)式編程從入門到走火入魔的過程。

很多人都在談論函數(shù)式編程(Functional Programming),只是很多人站在不同的角度看到的是完全不一樣的風景。堅持實用主義的 Python 老司機們對待 FP 的態(tài)度應該更加包容,雖然他們不相信銀彈,但冥冥中似乎能感覺到 FP 暗合了 Python 教義(The Zen of Python)的某些思想,而且既然 Python 是一門多范式編程語言,并在很大程度上支持函數(shù)式編程,那就更沒有理由拒絕它。

函數(shù)式編程源自于數(shù)學理論,它似乎也更適用于數(shù)學計算相關的場景,因此本文以一個簡單的數(shù)據(jù)處理問題為例,逐步介紹 Python 函數(shù)式編程從入門到走火入魔的過程。

問題 :計算 N 位同學在某份試卷的 M 道選擇題上的得分(每道題目的分值不同)。

首先來生成一組用于計算的偽造數(shù)據(jù):

            # @file: data.py
import random
from collections import namedtuple

Student = namedtuple('Student', ['id', 'ans'])

N_Questions = 25
N_Students = 20

def gen_random_list(opts, n):
    return [random.choice(opts) for i in range(n)]

# 問題答案 'ABCD' 隨機
ANS   = gen_random_list('ABCD', N_Questions)
# 題目分值 1~5 分
SCORE = gen_random_list(range(1,6), N_Questions)

QUIZE = zip(ANS, SCORE)
students = [
    # 學生答案為 'ABCD*' 隨機,'*' 代表未作答
    Student(_id, gen_random_list('ABCD*', N_Questions))
    for _id in range(1, N_Students+1)
]

print(QUIZE)
# [('A', 3), ('B', 1), ('D', 1), ...
print(students)
# [Student(id=1, ans=['C', 'B', 'A', ...
          

入門

首先來看常規(guī)的面向過程編程風格,我們需要遍歷每個學生,然后遍歷每個學生對每道題目的答案并與真實答案進行比較,然后將正確答案的分數(shù)累計:

            import data
def normal(students, quize):
    for student in students:
        sid = student.id
        score = 0
        for i in range(len(quize)):
            if quize[i][0] == student.ans[i]:
                score += quize[i][1]
        print(sid, '\t', score)

print('ID\tScore\n==================')
normal(data.students, data.quize)
"""
ID  Score
==================
1    5
2    12
...
"""
          

如果你覺得上面的代碼非常直觀且合乎邏輯,那說明你已經(jīng)習慣按照計算機的思維模式進行思考了。通過創(chuàng)建嵌套兩個? for ?循環(huán)來 遍歷 所有題目答案的判斷和評分,這完全是為計算機服務的思路,雖然說 Python 中的? for ?循環(huán)已經(jīng)比? C ?語言更進了一步,通常不需要額外的狀態(tài)變量來記錄當前循環(huán)的次數(shù),但有時候也不得不使用狀態(tài)變量,如上例中第二個循環(huán)中比較兩個列表的元素。函數(shù)式編程的一大特點就是盡量拋棄這種明顯 循環(huán)遍歷 的做法,而是把注意集中在解決問題本身,一如在現(xiàn)實中我們批改試卷時,只需要將兩組答案 并列 進行比較即可:

            from data import students, QUIZE

student = students[0]

# 將學生答案與正確答案合并到一起
# 然后過濾出答案一致的題目
filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, QUIZE))

print(list(filtered))
# [('A', ('A', 3)), ('D', ('D', 1)), ...]
          

然后再將所有正確題目的分數(shù)累加起來,即可:

            from functools import reduce

reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
print(reduced)
          

以上是對一位學生的結果處理,接下來只需要對所有學生進行同樣的處理即可:

            def cal(student):
    filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, QUIZE))
    reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
    print(student.id, '\t', reduced)

print('ID\tScore\n==================')
# 由于 Python 3 中 map 方法只是組合而不直接執(zhí)行
# 需要轉換成 list 才能將 cal 方法的的結果打印出來
list(map(cal, students))

"""
ID  Score
==================
1    5
2    12
...
"""
          

上面的示例通過? zip/filter/reduce/map ?等函數(shù)將數(shù)據(jù)處理的方法 打包 應用到數(shù)據(jù)上,實現(xiàn)了基本的函數(shù)式編程操作。但是如果你對函數(shù)式有更深入的了解,你就會發(fā)現(xiàn)上面的? cal ?方法中使用了全局變量? QUIZE ,這會導致在相同輸入的條件下,函數(shù)可能產(chǎn)生不同的輸出,這是 FP 的大忌,因此需要進行整改:

            def cal(quize):
    def inner(student):
        filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, quize))
        reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
        print(student.id, '\t', reduced)
    return inner
map(cal(QUIZE), students)
          

如此借助閉包(Closure)的方法,就可以維持純凈的 FP 模式啦!

走火(fn.py)

也許看了上面的 FP 寫法,你還是覺得挺啰嗦的,并沒有達到你想象中的結果,這時候就需要呈上一款語法糖利器:fn.py! fn.py ?封裝了一些常用的 FP 函數(shù)及語法糖,可以大大簡化你的代碼!

            pip install fn
          

首先從剛剛的閉包開始,我們可以用更加 FP 的方法來解決這一問題,稱為柯里化,簡單來說就是 允許接受多個參數(shù)的函數(shù)可以分次執(zhí)行,每次只接受一個參數(shù)

            from fn.func import curried
@curried
def sum5(a, b, c, d, e):
    return a + b + c + d + e

sum3 = sum5(1,2)
sum4 = sum3(3,4)
print(sum4(5))
# 15
          

應用到上面的? cal ?方法中:

            from fn.func import curried

@curried
def cal(quize, student):
    filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, quize))
    reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
    print(student.id, '\t', reduced)

map(cal(QUIZE), students)
          

在 FP 中數(shù)據(jù)通常被看作是一段數(shù)據(jù)流在一串函數(shù)的管道中傳遞,因此上面的 reduce filter 其實可以合并:

            reduce(lambda x, y: x + y[1][1], filter(lambda x: x[0] == x[1][0], zip(student.ans, quize)), 0)
          

雖然更簡略了,但是這樣會大大降低代碼的可讀性(這也是 FP 容易遭受批評的一點),為此? fn ?提供了更高級的函數(shù)操作工具:

            from fn import F

cal = F() >> (filter, lambda x: x[0]==x[1][0]) >> (lambda r: reduce(_+_[1][1], r, 0))
# 計算一名學生的成績
print(cal(zip(student.ans, QUIZE)))

# 然后組合一下
@curried
def output(quize, student):
    cal = F() >> (filter, lambda x: x[0]==x[1][0]) >> (lambda r: reduce(_+_[1][1], r, 0))
    print(student.id, '\t', cal(zip(student.ans, quize)))
map(output(QUIZE), students)
          

入魔(Hy)

如果你覺得上面的代碼已經(jīng)足夠魔性到看起來不像是 Python 語言了,然而一旦接受了這樣的語法設定感覺也還挺不錯的。如果你興沖沖地拿去給 Lisp 或 Haskell 程序員看,則一定會被無情地鄙視,于是你痛定思痛下定決心繼續(xù)挖掘 Python 函數(shù)式編程的奧妙,那么恭喜你,組織歡迎你的加入: Hail Hydra

哦不對,說漏了,是 Hi Hy

Hy?是基于 Python 的 Lisp 方言,可以與 Python 代碼進行完美互嵌(如果你更偏好 PyPy,同樣也有類似的Pixie),除此之外你也可以把它當做一門獨立的語言來看待,它有自己的解釋器,可以當做獨立的腳本語言來使用:

            pip install git+https://github.com/hylang/hy.git
          

首先來看一下它的基本用法,和 Python 一樣,安裝完之后可以通過? hy ?命令進入 REPL 環(huán)境:

            => (print "Hy!")
Hy!
=> (defn salutationsnm [name] (print (+ "Hy " name "!")))
=> (salutationsnm "YourName")
Hy YourName!
          

或者當做命令行腳本運行:

            #! /usr/bin/env hy
(print "I was going to code in Python syntax, but then I got Hy.")
          

保存為? awesome.hy

            chmod +x awesome.hy
./awesome.hy
          

接下來繼續(xù)以上面的問題為例,首先可以直接從 Python 代碼中導入:

            (import data)

;; 用于 Debug 的自定義宏
;; 將可迭代對象轉化成列表后打印
(defmacro printlst [it]
    `(print (list ~it)))

(setv students data.students)
(setv quize data.QUIZE)

(defn cal [quize]
  (fn [student]
    (print student.id
      (reduce
        (fn [x y] (+ x (last (last y))))
        (filter
          (fn [x] (= (first x) (first (last x))))
          (zip student.ans quize))
        0
      )
    )
  )
)

(printl (map (cal quize) students))
          

如果覺得不放心,還可以直接調用最開始定義的方法將結果進行比較:

            ;; 假設最上面的 normal 方法保存在 fun.py 文件中
(import fun)
(.normal fun students quize)
          

總結

以一個簡單的數(shù)據(jù)處理問題為例,我們經(jīng)歷了 Python 函數(shù)式編程從開始嘗試到“走火入魔”的整個過程。也許你還是覺得不夠過癮,想要嘗試更 純粹 的 FP 體驗,那么 Haskell 將是你最好的選擇。FP 將數(shù)據(jù)看做數(shù)據(jù)流在不同函數(shù)間傳遞,省去不必要的中間變量,保證函數(shù)的純粹性…等等這些思想在數(shù)據(jù)處理過程中還是非常有幫助的(Python 在這一領域的競爭對手 R 語言本身在語法設計上就更多地受到 Lisp 語言的影響,雖然看起來語法也比較奇怪,但這也是它比較適合用于數(shù)據(jù)處理及統(tǒng)計分析的原因之一)。

參考

  1. Tips ? 0x02-函數(shù)式編程
  2. Python HOWTOs ? Functional Programming HOWTO
  3. Hy's Doc
  4. fn.py

更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 最新中文字幕在线 | 91亚洲国产 | 色屁屁www影院免费观看视频 | 国产成人一区二区三区电影 | 欧美一级特黄aa大片视频 | 看免费一级毛片 | 精品欧美一区二区久久久伦 | 人人看人人舔 | 最近最新中文字幕 | 日本一区免费在线观看 | 国产乱码在线观看 | 欧美亚洲理伦电影毛片在线播放 | 日韩亚洲第一页 | 欧美精品导航 | 亚洲欧美无人区乱码 | 加勒比精品久久一区二区三区 | japanese xxxxhd| 亚洲欧美天堂综合久久 | 亚洲天堂网在线观看 | 国产一级在线观看视频 | 国产欧美日韩在线不卡第一页 | 韩日在线视频 | 国产国产成人久久精品杨幂 | 欧美一级成人免费大片 | 亚洲www. | 91香蕉人成app | aⅴ在线免费观看 | 九九51精品国产免费看 | 奶子吧naiziba.cc免费午夜片在线观看 | 国内精品视频 在线播放 | 首页亚洲国产丝袜长腿综合 | 亚洲精品乱码久久久久久v 国产高清免费视频 | 中文字幕日韩理论在线 | 人人草人人干 | 欧美高清不卡午夜精品免费视频 | 制服丝袜成人动漫 | 日色视频| 日本一级α片 | www.奇米第四色 | 成人亚洲视频在线观看 | 成人午夜免费福利 |