Python与Erlang函数性的对比(一)
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 =:=0, Y rem 2 =:=0]. |
上面是列表推导式在Python和Erlang中的区别。为了看懂上面的表达式,我做几点说明,也算科普下基本知识。
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(Total, 0) -> Total;
sum(Total, X) ->
sum(Total+X, X-1).
s(X) ->
sum(X, X-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关键字是区别,这个关键字是在函数内部引用并重新绑定(修改)全局变量