[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
map(f, [x1, x2, ..., xn]) = [f(x1), f(x2), ..., f(xn)]
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
登入後複製
sortedsorted 函數同樣是一個高階函數,對參數key 傳遞函數可以將需要排列的序列經過key 函數處理後再進行排序,不過不會改變序列的值,例如: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([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
登入後複製
裝飾器(decorator)匿名函數就不說了,以後用時再仔細看吧,裝飾器我記得之前看flask 的時候都研究了好久,這次再來複習一下。 簡單裝飾器首先是一個簡單的裝飾器,在每次調用函數前打印出日誌:>>> sorted([36, 5, -12, 9, -21], key=abs) [5, 9, -12, -21, 36]
import logging
def log(func):
def wrapper(*args, **kw):
logging.warn("%s is running" % func.__name__)
func(*args, **kw)
return wrapper
登入後複製
這就是一個極其簡單的裝飾器,如何使用它呢?我最先看到的用法是在需要裝飾的函數前面加上@,但其實這是Python 的一個語法糖,最原始的用法反而更能讓人理解,先定義一個函數f:
import logging def log(func): def wrapper(*args, **kw): logging.warn("%s is running" % func.__name__) func(*args, **kw) return wrapper
def f(): print("in function f") f = log(f)
>>> f() WARNING:root:f is running in function f
@log def f(): print("in function f")
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 屬性: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 不变
>>> def f():
... print("in function f")
...
>>> f.__name__
'f'
#对于添加装饰器的函数,其 name 改变了
>>> @log
... def f():
... print("in function f")
...
>>> f.__name__
'wrapper'
登入後複製
聯繫到最前面的裝飾器賦值語句,就可以大致明白髮生了什麼:#对于不加装饰器的 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)))

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

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

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

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

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

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

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

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

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