這里我不討論 python 的一些有用的庫或者框架,只從語言本身,最小支持的情況下談論這門語言本身。語言的發展都是越來越接近Lisp,這也是Lisp這門語言偉大的原因。
下面我羅列一下我學習 python 的原因:
多編程范式
python是一門多范式的編程語言,所謂的過程式,面向對象和函數式的結合。
大部分人接觸編程語言都是從過程式開始的,原因是因為過程式的程序方式與計算機運行方式是統一的,指令序列與運行過程是統一的。如典型的C,我也是從C開始學習的,過程式的程序語言設計編寫程序較為簡單,但是符合人機交互思考方式。
python雖然是一門面向對象語言,就連“ ”(空格)也可以看做是一個對象,但是python勝任過程式是沒有問題的。
如不需要使用類的靜態方法:
1
2
|
def a_plus_b(a,b): return a + b |
1. Duck typing
Python在設計的時候將其當做一門面向對象的方式編寫,且不說面向對象給軟件設計帶來的一些革命等,在python這樣的動態語言中面向對象有一個亮點就是Duck typing(鴨子類型)。
關于鴨子類型,就是說,如果我認為一個抽象的東西會游泳會“嘎嘎”叫,我就可以把它當做鴨子。
1
2
3
4
5
6
7
8
|
def use_duck( Duck ): Duck.swim() Duck.gaga() class Duck: def swim( self ): ... def gaga( self ): ... |
如果這樣使用:
little_duck = Duck()
use_duck( little_duck )
關于Duck類,你可以給他取任何的名字,或者繼承它取另一個名字,只需要實現 swim() gaga() 你就可以把它當做鴨子。
關于鴨子類型,很多人不理解為什么不需要提供一個接口來規定鴨子的行為,我既不支持也不反對,我的觀點是這樣的:
- 對于參數的檢查,不符合動態語言的特性
- 提供了接口規范,那就不是鴨子類型了,直接叫多態得了
2. Python支持的函數式編程
首先是lambda 演算。
函數式編程的定義是將函數看做是變量一樣的待遇,變量在程序中最簡單的有什么待遇呢?
- 可以賦值
- 可以作為參數
- 可以改變值(Erlang例外)
- 且不說生命周期了和作用域了
λ演算背后蘊含著計算機可計算性的深厚知識,lambda也是圖靈模型,是停機問題的一個否定答案,不僅僅是一個匿名函數那樣簡單。
關于 lambda 演算,看看這個程序做了什么:
1
|
map ( lambda n: 2 * n,[ 1 , 2 , 3 , 4 , 5 ]) |
lambda n:2*n 本身作為一個匿名函數
lambda 本身作為一個參數傳入 map()函數,這也就是說我的高階函數,可以將函數變身看成是一個變量作為參數傳遞,這也是它作為函數受到的高等待遇
關于賦值和改變值,兩種方式:
f = fun() 不改變函數狀態,只改變名稱,但是說明函數是可以賦值的
可以使用閉包作為改變函數的狀態方式,或者使用裝飾器來完成函數狀態改變
函數式編程的使用也可以提高程序的可讀性和減少代碼,而且能夠清晰的表達函數的功能,如MapReduce就是來自函數式編程的思想:
1
|
Map (func, List ) |
作用是將func 作用于List中的每一個元素。
以剛才的例子舉例:
1
|
map ( lambda n: 2 * n,[ 1 , 2 , 3 , 4 , 5 ]) |
此函數返回
1
|
[ 2 , 4 , 6 , 8 , 10 ] |
重要的是在于知道這樣的方式帶給我們的清晰的設計方式。
當然函數式編程不是那么幾句話就說完的,理解函數式編程的核心是理解 λ演算。
一些有意思的特性
1. 惰性計算:
看看完成一個斐波那契數列 python 可以怎么做:
1
2
3
4
5
6
7
|
>>> def fib(): a , b = 0 , 1 while 1 : yield b a , b = b ,a + b >>> f = fib() |
實際上由yield 生成了一個可迭代對象,每次調用f.next()就可以產生一個斐波那契值,而函數的內部狀態是由迭代對象存儲的。至于返回一個可迭代對象,如果需要確定迭代到多少位,可以使用 itertools.islice。
2. 協程
協程也是一個基于yield的概念,主要的模式是微線程的協作式工作模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
def coroutine(func): def ret(): f = func() f. next () return f return ret @coroutine def consumer(): print "Wait to getting a task" while 1 : n = ( yield ) print "Got %s" ,n import time def producer(): c = consumer() while 1 : time.sleep( 1 ) print "Send a task to consumer" c.send( "task" ) if __name__ = = "__main__" : producer() |
協程帶來的好處是可以直接調度你的線程,這也是它為什么叫做協程而不是線程的原因,線程屬于搶占式并發,協程屬于協作式并發。
動態語言帶來的好處
從程序設計帶來的快感(我相信只有熱愛這方面的人才有的感覺)來說,動態語言,比如python,節約了更多的時間可以用來陪女朋友或者老婆,或者老公。
當然,作為互聯網時代快速開發來說,趕鴨子上線,也是《黑客與畫家》上面介紹的,快速開發很重要,當然需要符合這方面的需求。
動態語言的CPU密集型運算必然比不過C/C++。
總之:人生苦短,我用python。