定义
函数式编程就是一种抽象程度很高的编程范式.它的特点是:
1. 把函数本身作为参数传入另一个函数
2. 返回一个函数
高阶函数(High-order function)
定义
一个函数可以接受另一个函数作为参数,这种函数就称为高阶函数.
另一种说法就是把函数本身作为参数传入另一个函数,对应了第一个特点.
这里比较难理解的就是为什么函数可以把函数本身传入另一个函数.
我们可以分开进行理解:
根据一般的规律,函数的参数一般都是传入变量,那么一个函数可以当作参数传入那函数是不是变量呢?
我们一般说的某某函数比如求绝对值的函数abs
,其实只是说的的它的函数名,一个具有某个功能的函数可以拥有很多个函数名,就如我们的宠物狗,我们可以叫它任何我们喜欢的名字,若是没有名字,也不代表这只狗它不是狗了,它还是具有狗的一切特征.
在编程上来说函数就是占据计算机内存的具有某种功能的那么一种东西,在面对对象语言(OOP)中我们称之为对象,python也是OOP语言.我们也可以为某个函数对象起赋予他任何我们喜欢的名字,不过一般还是按照方便理解的方式来起函数名.
不过函数对象和动物还是有区别的,动物没有名字可以生存,但是函数对象没有相应的变量对其引用就会被垃圾回收器回收消灭.
>>> def fun(x): # 创建函数,并在占用一部分内存
... print 'Hello: ', x
...
>>> fun('Han mei mei') # 通过指出函数名和传入参数来调用函数
Hello: Han mei mei
>>> fun
<function fun at 0x7f29e33e0668> # 显示函数在内存中的位置
在创建函数fun(x)
后,Python将其视为一个对象并在内存中给fun(x)
开辟一块空间.fun函数名只是作为一个引用变量来指向fun(x)
,所以我们可以用别的引用变量来指向fun(x)
函数.比如:
>>> fun
<function fun at 0x7f29e33e0668>
>>> f = fun
>>> f
<function fun at 0x7f29e33e0668> #内存地址与fun相同
>>> f('Li lei')
Hello: Li lei
>>> def fun_change(y):
... print 'After_change: ',y
...
>>> fun = fun_change #将fun函数名指向其它函数
>>> fun
<function fun_change at 0x7f29e33e06e0> #fun的内存地址已经改变
>>> fun('Li lei')
After_change: Li lei
>>> f
<function fun at 0x7f29e33e0668> #f还是指向原来的fun函数的内存地址.
>>> f('Han mei mei')
Hello: Han mei mei
这里有点难理解.我们可以把函数看作是一个电视,fun(x)
是这个电视的遥控器,电视只有一个,但是控制电视的遥控器可以有很多个,这里有点和Java类似.
// 在Java中实现fun(x)的调用
public class func { //创建类(class):func,Java会在内存堆中给func类分配一个内存空间.
public static void main(String[] args) {
func f = new func(); //创建新类f,f为类func的引用变量,
f.fun("Han mei mei"); //调用fun(String x)方法,方法相当于Python中的函数
}
public void fun(String x) {
System.out.println("Hello: " + x);
}
}
> Hello: Han mei mei
函数本身其实是函数名变量对函数的引用
>>> def fun(x):
... pass
...
>>> fun
<function fun at 0x7fc805732578>
>>> f = fun
>>> f
<function fun at 0x7fc805732578>
总的来说函数名也是变量,只要是变量就可以作为参数传入其它的函数,这也就说明了为什么一个函数可以传入另一个函数.
>>> def fun(x,y,i):
... return i(x) + i(y)
...
>>> fun(-9,10,abs) #传入-9, 10, 函数abs(求绝对值)
19
我们来看下计算过程
> x => -9
> y => 10
> i => abs
> i(x) + i(y) => abs(-9) + abs(10) = 19
map()
和reduce()
定义
map()
和reduce()
是python内建的高阶函数.
map()
函数接收两个参数,一个是函数,一个是list,map()
将函数依次作用于list的每个元素,并把结果组装成list返回.
可以换种说法就是用传入的函数遍历数组并把计算结果再次组装成数组输出.
map()
的结构: `
map(function, list1,list2,....) #list的数量=函数参数个数
map()
例子:
>>> def mp(x): #一个参数
... return x*x
...
>>> map(mp, range(10)) #传入一个参数
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> def mp(x,y): #两个参数
... return x+y
...
>>> map(mp, range(10),range(10)) #传入两个参数
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
reduce()
函数也是接收两个参数,一个是函数,一个是list,但是与map()
不同reduce()
的函数必须接收两个参数,reduce()
将函数的计算结果与list的下一个元素做累计运算.
reduce()
的结构
def fun(x,y):
pass
reduce(fun, list)
reduce()
例子
>>> def re(x,y): #两个元素
... return x+y
...
>>> reduce(re, range(10)) #对list进行累加
45
>>> def re(x,y,z):
... return x+y+z
...
>>> reduce(re,range(10))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: re() takes exactly 3 arguments (2 given) #三个参数Error
>>> def re(x,y,z,i):
... return x+y+z+i
...
>>> reduce(re,range(10))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: re() takes exactly 4 arguments (2 given)#四个参数Error
filter()
定义
filter()
是python内建函数,用于对列表的过滤.同map()
和reduce()
一样,filter()
也是接收一个函数和一个list,把函数依次带入list上的元素,然后根据函数判断得出的True
和False
来确定是否取得或抛弃该元素.
>>> def fun(x):
... return x%2 == 1
...
>>> map(fun, range(10))
[False, True, False, True, False, True, False, True, False, True]
#将判断结果全部输出
>>> filter(fun, range(10))
[1, 3, 5, 7, 9]
#根据判断结果,对结果为`Ture`的进行取数
sorted
定义
sorted()
也是内置函数,对列表进行排序.
>>> L = [23, 20, 8, 1, 18]
>>> sorted(L)
[1, 8, 18, 20, 23]
对于数字可以通过比较大小直接进行排序,但是string
或着dict
呢?通常我们规定两个元素x
和y
两个元素,如果x>y
则返回1
,x==y
返回0
,x<y
返回-1
.
大小 | 返回值 |
---|---|
x > y | 1 |
x == y | 0 |
x < y | -1 |
我们比较下字母表
>>> alpha = ['a','B','c','D','e','F']
>>> sorted(alpha)
['B', 'D', 'F', 'a', 'c', 'e'] #为什么不一样呢?因为对于string的排序是按照ASCII的较大小的
>>> map(ord, sorted(alpha)) #ord函数把字母转换成对应的ASCII编码序号
[66, 68, 70, 97, 99, 101]
>>> map(chr, map(ord, sorted(alpha))) #chr函数把与ord功能相反
['B', 'D', 'F', 'a', 'c', 'e']
我们发现大小写对排序有影响,如何排除这个影响呢?我们只要把字母大小统一成一样的就可以了.
>>> def ignore_case(x1, x2):
... y1 = x1.upper() #upper()将字母转换为大写
... y2 = x2.upper()
... if y1 < y2:
... return -1
... if y1 > y2:
... return 1
... return 0
...
>>> sorted(['B','a','D','b','C'], ignore_case) #sorted也是高阶函数,可以接受一个比较函数来实现自定义排序
['a', 'B', 'b', 'C', 'D']
后面有更简洁的方法来实现上面代码的功能
更简洁的方法
1.key
关键词,适用于list.sort()
和sorted()
,它的作用是在比较之前去调用list中的每个函数,然后再传给sorted()
进行比较.
注意key
关键词后面跟的必须是一个函数且函数只能结婚搜一个参数.
>>> alpha.sort()
>>> alpha
['B', 'D', 'F', 'a', 'c', 'e']
>>> sorted(alpha, key=str.lower) #str.lower将字符串转为小写.
['a', 'B', 'c', 'D', 'e', 'F']
更常用的一个功能就是对以复杂对象的某一个参数为索引进行排序
>>> human = [
... ('Li lei', 'male', 10),
... ('Han mei mei', 'famale',9),
... ('Xiao ming', 'male', 11),
... ('Xiao hong', 'famale',8),
... ]
>>> sorted(human, key=lambda human: human[2]) #以年龄为索引排序
[('Xiao hong', 'famale', 8), ('Han mei mei', 'famale', 9), ('Li lei', 'male', 10), ('Xiao ming', 'male', 11)]
2.reverse
关键词,反转当前排序.可以实现正序和倒序排列.
>>> sorted(human, key=lambda human: human[2]) #无reverse,默认不开启
[('Xiao hong', 'famale', 8), ('Han mei mei', 'famale', 9), ('Li lei', 'male', 10), ('Xiao ming', 'male', 11)]
>>> sorted(human, key=lambda human: human[2],reverse=True) #开启reverse
[('Xiao ming', 'male', 11), ('Li lei', 'male', 10), ('Han mei mei', 'famale', 9), ('Xiao hong', 'famale', 8)]
>>> sorted(human, key=lambda human: human[2],reverse=False) #关闭reverse
[('Xiao hong', 'famale', 8), ('Han mei mei', 'famale', 9), ('Li lei', 'male', 10), ('Xiao ming', 'male', 11)]
可以看到reverse
默认是False
不开启的,若是想使用到序需要自己将reverse
关键词改为True
.