Python與Erlang函數性的對比(一)

PythonErlang函數性的對比(一)

1. 列表推導式:

Python

Erlang

基本的

[n*n for n in [1,2,3,4]]

[N*N || N <-[1,2,3,4]].

帶條件判斷的

[n*n for n in [1,2,3,4] if n%2 == 0]

[N*N || N <-[1,2,3,4], N rem 2 =:= 0].

多變量

[(x,y) for x in [1,2,3,4] for y in [1,2,3,4] if x%2==0 and y%2==0]

[{X,Y} || X<-[1,2,3,4], Y<-[1,2,3,4], X rem 2 =:=0Y rem 2 =:=0].

 

上面是列表推導式在PythonErlang中的區別。爲了看懂上面的表達式,我做幾點說明,也算科普下基本知識。

1. 關於變量的說明:

共同點:變量不用聲明類型,都是動態類型綁定。

區別:Erlang中變量名大寫,小寫的是原子,而Python中沒有要求,但建議變量名使用駝峯標示;Python中可以修改變量的值,而Erlang中變量的值一旦賦值,則不能再改變。

2. 關於元組的說明:

共同點:二者都是不可改變的,一經定義,不再可變,常用於函數的返回值,元組可以嵌套定義;另外取值的時候都可以模式匹配取值。

區別:定義方式不同:Python中定義元組使用()Erlang中定義元組使用{}

3. 列表的說明:

共同點:列表的定義方式一樣都是[]

區別:Python中隊列表的操作取值方法很多,Erlang中也有一些方法,比如++ -- 二者是不同的。

4. 關於相等符號:

Python中是常規的==, Erlang中有== =:=兩種,

5. 關於列表推導式:

列表推導式是爲了簡化命令式編程的循環,Python中使用for關鍵字,而Erlang中使用||符號

2.map, filter函數:

Python

Erlang

map

map(lambda x: 2*x, [1,2,3,4])

lists:map(fun(X-> 2*X end,[1,2,3,4]).

filter

map(lambda x: 2*x, [1,2,3,4])

lists:filter(fun(X-> X rem 2 =:= 0 end, [1,2,3,4]).

關於上面的幾點說明:

1. 匿名函數的說明:

相同點: 函數沒有名字(這是廢話)

區別:python中使用lambda創建匿名函數,格式爲lambda arg1, arg2: <expression> 

Erlang中匿名函數的格式爲fun(Args1) -> Exp1, Exp2, ....ExpN; (Args2) -> Exp1, Exp2,... End

2. 關於Map Reduce函數

Map函數是將函數應用於列表中的每一個元素,完成後返回一個新的保存了每個列表中元素經過函數處理後的值。

Filter函數式將函數應用於列表中的每一個元素,完成後返回一個新的使元列表應用於函數值爲true的元素組成的列表。

3. 遞歸與尾遞歸

遞歸的定義相信學過編程語言的都知道,尾遞歸是針對傳統遞歸算法而言的,尾遞歸是從最後開始計算,每遞歸一次就算出相應的結果,也就是說,函數調用出現在調用者函數的尾部,因爲是尾部,所以根本沒有必要保存任何局部變量,直接讓被調用的函數返回時越過調用者,返回到調用者的調用者

Erlang中例子

%% 尾遞歸調用

sum(Total0-> Total;

sum(TotalX->

sum(Total+XX-1).

s(X-> 

sum(XX-1).

%% 遞歸調用

se(0-> 0;

se(X-> X + se(X-1)

Python 中例子

尾遞歸調用

def sum(total, x):

    if (x == 0):

        return total

    else:

        return sum(total+x, x-1)

def s(x):

    return sum(x, x-1)

遞歸調用

def se(x):

    if (x == 0):

        return 0

    else:

        return x + se(x-1)

測試結果:

python中尾遞歸並沒有轉換爲循環,依然會報RuntimeError: maximum recursion depth exceeded,在erlang中正常,這種尾遞歸在Oracle jdk中一樣會報堆棧溢出錯誤。

4. 閉包

閉包簡單來說就是在一個函數中包括了另一個函數,關於閉包的價值有兩點:

1. 保護函數內的變量安全性和可訪問性

2. 在內存中維持一個變量

Erlang中的閉包的定義是通過fun函數:

base(A->

B = A + 1,

F = fun() ->

A * B

end,

F().

簡潔版的:

base(A->

B = A + 1,

(fun() ->

A * B

end)().

由於Erlang中變量的不變形,匿名函數的上下文也是不變的

Python

def base(a):

    b = a+1

    def iner():

        return b

return iner()

Python中有一個有意思的問題,看看下面的代碼

def base(a):

    b = a+1

    def iner():

        b = b+1

        return b

    return iner()

這段代碼會報一個UnboundLocalError: local variable 'b' referenced before assignment

奇怪吧?

Python3.0以前,閉包能訪問外部函數的局部變量,但是不能修改外部函數的局部變量,

Python3.0爲此引入了nonlocal關鍵字,完善了閉包訪問外部變量的機制

def base(a):

    b = a+1

    def iner():

        nonlocal b

        b = b+1

        return b

return iner()

這樣在python3.0中就不會報異常了,注意和global關鍵字是區別,這個關鍵字是在函數內部引用並重新綁定(修改)全局變量

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章