目錄
函數式程式設計
高階函數
首頁 後端開發 Python教學 [python] 初探'函數式程式設計'

[python] 初探'函數式程式設計'

Feb 16, 2017 am 11:09 AM
python

函數式程式設計

上學期有上一門叫'人工智慧' 的課,老師強行要我們學了一個叫做prolog 的語言,哇那感覺確實難受,思維方式完全和之前學過的不一樣,寫個漢諾塔想了半天,最後還是在網上找了段代碼修改一下(怕被老師發現抄襲)才寫出來,貼一段出來感受一下:

hanoi(N) :- dohanoi(N, 'a', 'b', 'c').
dohanoi(0, _ , _ , _ )    :- !.
dohanoi(N, A, B, C)    :-
  N1 is N-1,
  dohanoi(N1, A, C, B),
  writeln([move, N, A-->C]), 
  dohanoi(N1, B, A, C).
登入後複製

當時是差不多弄懂了,主要是資料實在太少,debug 都無從談起,一遇上bug 就gg,我現在自己看也有點頭暈。不過據說 prolog 當年能和 Lisp 一爭高下,最近對 Lisp 也有點興趣,等弄完這些就去參拜一下這類函數式語言。

何謂函數式程式設計?廖大這裡寫道:

函數式程式設計就是一種抽象程度很高的程式設計範式,純粹的函數式程式語言所寫的函數沒有變量,因此,任意一個函數,只要輸入是確定的,輸出就是確定的,這種純函數我們稱之為沒有副作用。而允許使用變數的程式設計語言,由於函數內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數是有副作用的。

可能看完還是有些不太理解,不急,先看完這幾個小節吧。

高階函數

在數學和電腦科學中,高階函數是至少滿足下列一個條件的函數:

  • 接受一個或多個函數作為輸入

  • 輸出一個函數

    是說,把函數本身當成參數傳遞,或是回傳一個函數。
例如,可以像普通賦值一樣將函數賦值給變數:

>>> min(1, 2)
1
>>> f = min
>>> f(1, 2)
1
>>> f
<built-in function min>
>>> min
<built-in function min>
登入後複製
也可以給函數賦值(代碼接上):

>>> min = 10
>>> min(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> f(1, 2)
1
>>> min = f
>>> min(1, 2)
1
登入後複製
還可以傳參,例如,一個計算所有數字的和的函數:

>>> def add(a, b):
...     return a+b
...

>>> def mysum(f, *l):
...     a = 0
...     for i in l:
...             a = f(a, i)
...     return a
...
>>> mysum(add, 1, 2, 3)
6
>>> mysum(add, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
55
登入後複製
當然,將這個f 換成乘法就是計算所有數字的乘積了。

再來看看 python 內建的一些高階函數,常常會用到。

map/reduce

記得上學期上雲端運算的課程時依稀有聽過這個詞,不過這課很水,就沒怎麼聽,在這裡看到好像發現不太一樣? ?

不過沒啥說的,簡單說一下每個函數的作用。

對於 map,其計算式可以看成這樣:

map(f, [x1, x2, ..., xn]) = [f(x1), f(x2), ..., f(xn)]
登入後複製
對於 reduce,其計算式可以看成這樣:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
登入後複製
廖大那裡說得很清楚啦。

filter

filter 和 map 函數類似,接受一個函數和 iterable,傳回也是一個 list,不過其功能是根據函數傳回值是否為 True 來判斷是否保留該值。例如:

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
登入後複製

sorted

sorted 函數同樣是一個高階函數,對參數key 傳遞函數可以將需要排列的序列經過key 函數處理後再進行排序,不過不會改變序列的值,例如:

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
登入後複製

裝飾器(decorator)

匿名函數就不說了,以後用時再仔細看吧,裝飾器我記得之前看flask 的時候都研究了好久,這次再來複習一下。

簡單裝飾器

首先是一個簡單的裝飾器,在每次調用函數前打印出日誌:

import logging

def log(func):
    def wrapper(*args, **kw):
        logging.warn("%s is running" % func.__name__)
        func(*args, **kw)
    return wrapper
登入後複製

這就是一個極其簡單的裝飾器,如何使用它呢?我最先看到的用法是在需要裝飾的函數前面加上@,但其實這是Python 的一個語法糖,最原始的用法反而更能讓人理解,先定義一個函數f:

def f():
    print("in function f")

f = log(f)
登入後複製
這樣定義了之後,我們再呼叫f 函數:

>>> f()
WARNING:root:f is running
in function f
登入後複製
使用@log 的結果與其一樣,其實@符號作為裝飾器的語法糖,與前面的賦值語句具有相同的功能,使代碼看起來更簡潔明了,避免再一次賦值操作,就像下面這樣:

@log
def f():
    print("in function f")
登入後複製
含參數的裝飾器

有時候我們還需要向裝飾器中傳入參數,例如,狀態,層次等信息,只需要在wrapper 函數外再'包裹'一層函數,如下所示:

import logging

def log(level):
    def decorator(func):
        def wrapper(*args, **kw):
            logging.warn("%s is running at level %d" % (func.__name__, level))
            return func(*args, **kw)
        return wrapper
    return decorator

@log(2)
def f():
    print("in function f")
    
>>> f()
WARNING:root:f is running at level 2
in function f
登入後複製

進一步理解

為了再進一步理解裝飾器,我們可以打印出函數f 的name 屬性:

#对于不加装饰器的 f,其 name 不变
>>> def f():
...     print("in function f")
...
>>> f.__name__
'f'

#对于添加装饰器的函数,其 name 改变了
>>> @log
... def f():
...     print("in function f")
...
>>> f.__name__
'wrapper'
登入後複製

聯繫到最前面的裝飾器賦值語句,就可以大致明白髮生了什麼:

f = log(f)

使得f 指向修改為log(f) 的回傳值,即wrapper 函數。每次執行原函數 f 時,則會呼叫 wrapper 函數,在我們這個範例中,則是先列印日誌,然後執行原函數 f。

不過這樣有一個問題,這樣使得原函數f 的元資訊被替換了,關於f 的許多資訊消失不見,這是很難令人接受的,不過好在我們有functools 模組,修改函數為:

import functools
import logging

def log(func):
    functools.wraps(func)
    def wrapper(*args, **kw):
        logging.warn("%s is running" % func.__name__)
        func(*args, **kw)
    return wrapper

>>> @log
... def f():
...     print("in function f")
...
>>> f.__name__
'f'
登入後複製
另外,還可以對同一個函數添加多個裝飾器:

@a
@b
@c
def f ():


# 等价于

f = a(b(c(f)))
登入後複製
總結

關於函數式編程我也不是很了解,這裡只是大概了解了一下其概念吧,平時肯定還是使用命令式編程用得多。不過有語言是純函數式語言,例如 Haskell 或 Lisp,學習它們會讓人打開一種新思路。

更多[python] 初探'函數式程式設計'相關文章請關注PHP中文網!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

See all articles