函数式编程
高阶函数
函数不止可以接受变量,还可以接受函数。其实函数名本身就是一种变量,也是可以指向的。而接受函数作为参数的函数就称之为高阶函数。
map和reduce
map函数就是一个高阶函数,它接受两个参数,其中一个是函数,另一个是iterable。 iterable中的每一个元素都会被接受的这个函数作用一次,并最终返回。注意map函数的结果并不是一个list或者tuple,dic,set.而是一个iterator。
列如,我们现在要得到一个11+22+33+……+100100,用map函数怎么做呢?
def f(x):
return(x*x)
r=map(f,range(1,101)
print(sum(list(r)))
可以看到,range(1,101)中的100个元素都被函数f(x)作用了一次,并储存在iterator中。需要用list函数把它转化成list后才能求和,当然,也可以用next函数取出其中包含的值。
reduce也是可以接受两个参数,一个是函数,一个是iterable.但是,它于map不同的有两点,第一点是接受的函数,reduce中的函数可以接受两个参数,并且其中一个参数是上一次运算的结果。第二点就是最后的结果,map函数最后的结果是一个iterator,需要用list或者next才能取出其中的值,而reduce的结果并不是iterator。还有一个要注意的就是调用reduce函数前需要在代码上加一行,from functools import reduce.从functools中调用reduce函数。
下面举一个例子。将一个list中的元素转化成int,比如说把[1,2,3,6,2,4]转化成123624.
from functools import reduce
def char_num(*n):
def num(x,y):
return(10*x+y)
m=reduce(num,n)
课后题
1.利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:[‘adam’, ‘LISA’, ‘barT’],输出:[‘Adam’, ‘Lisa’, ‘Bart’]
def normalize(name)
return(name[0].upper(),name[1:].lower())
print(map(normalize,['adam', 'LISA', 'barT']))
2.利用map和reduce编写一个str2float函数,把字符串’123.456’转换成浮点数123.456
from functools import reduce
def str2float(s):
a={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
def D(x):
return(a[x])
def f(x,y):
return(10*x+y)
s=s.split('.')
m_1=reduce(f,map(D,s[0]))
m_2=reduce(f,map(D,s[1]))/(10**len(s[1]))
return(m_1+m_2)
print('str2float(\'123.456\') =', str2float('123.456'))
if abs(str2float('123.456') - 123.456) < 0.00001:
print('测试成功!')
else:
print('测试失败!')
学习了reduce和map函数的用法,注意调用reduce函数时要在开头加一段from functools import reduce
reduce函数使用时里面的第一个变量是一个函数,函数可以接受两个值,开始时函数作用于
开始的两个值,然后计算的结果作为其中一个值,再接受第三个值,函数再作用于这两个值
再一直循环下去
s.split(’.’)的作用是将一个interable以“."为分界线分成两部分
小数部分的处理是先将数字组装成整数,再除以10**len(小数部分)
filter
filter也是一个高阶函数,它也是接受两个参数,一个函数,一个iterable。它参数中的函数return回的是true或者False。如果返回的是True,那么,filter就会返回原先进去的那个自变量。如果返回的是False,那么filtër就不会返回。而且要注意,filter返回的结果是一个iterator。
列如:
def f_2n(n):
return(n%2==0)
#这个函数的作用是判断一个数是否是二的倍数
m=list(filter(f_2n,range(1,101))#生成一个list其中的元素是1到100之间的偶数。
课后题
回数是指从左向右读和从右向左读都是一样的数,例如12321,909。请利用filter()筛选出回数
def is_palindrome(n):
return(str(n[:]==str(n[::-1])
#反向切片,并把两个列表转化成str进行比较,因为我只需判断它反向过来后于原来是否相等。
sorted
sorted也是一个高阶函数,但是它接受的函数参数是固定的,是一个映射函数,虽然我们可以通过改变key来改变映射的对象,但是,它排序的本领是不会发生改变的。
课后题
假设我们用一组tuple表示学生名字和成绩:
L = [(‘Bob’, 75), (‘Adam’, 92), (‘Bart’, 66), (‘Lisa’, 88)]
请用sorted()对上述列表分别按名字排序:
def by_name(t):
return(t[0])
L_1=sorted( [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)],key=by_name)
print(L_1)
这个题目的关键是如何将元组中的元素拿出来,注意到sorted函数是将L迭代一遍,其中的每一个元素都会被单独拿出来,这样的话就可以先让sorted把L[0]拿出来,再把key看做拿出来的那个元组的第一个元素,所以函数by_name的作用就是拿出元组的中第一个元素
返回函数 return
return不仅可以返回函数计算的结果,也可以返回一个函数。比如说,
def f(*x):
def g():
sum=0
for a in x:
sum=sum+a
return(sum)
return(g)
L=f(1,2,3)
#在powershell里面输入L,结果是<function f.<locals>.g at 0x00592DF8>,当调用L()时,返回的结果是6
从上面这个例子中就可以看出return还可以返回一个函数的形式,要注意只是一个形式,并不会计算结果,只有当你再次调用的时候,它才会把数值代入进去计算。下面这个例子可以说明这个问题。
def f(*x):
k=[]
for a in x:
def g():
return(a*a)
k.append(g)
return(k)
L=f(1,2,3)
L1,L2,L3=L()
#在这个例子里面,L实际上是[x*x,x*x,x*x]而不是[1,4,9].a是一个外部的变量,内部函数在计算的时候无法调用外部变量,内部函数保存的是一个函数的形式,不是函数计算的结果。所以最终L1,L2,L3的结果都是9
匿名函数 lambda
用于简化函数形式。例如
def f(x):
return x*x
L=list(map(f,range(10)))
#也可以写成
L=list(map(lambda x:x*x,range(10)))
课后作业
用匿名函数改造下列代码
def is_odd(n):
return n%2==1
L=list(filter(is_odd,range(1,20)))
L=list(filter(lambda n:n%2==1,range(1,20)))
就写到这吧,博客还是随缘写吧。