python高阶函数和柯里化
高阶函数
在Python中,函数算是一等公民(first class object),但它也是属于对象,而且还是可调用的对象。函数名可以作为普通变量使用,同时还可以作为其他函数的参数,返回值。而这就引申出了高阶函数的定义!
高阶函数:在数学和计算机科学中,满足下面两条件的任意条件的函数就是高阶函数。
- 接受一个或者多个函数作为参数。
- 输出一个函数(也就是返回值为函数)
比如下面的这个函数。
def counter(base): def inc(step=1): base+=step return base return inc
但是上面的函数定义有一个问题,内层函数引用了外层函数的变量,但是却又在里面重新定义。所以运行的时候会报错。改进办法是加一个nonlocal。
def counter(base): def inc(step=1): nonlocal base base+=step return base return inc foo = counter(5) foo() 结果为: 6
上面的代码,f1 = counter(5)和f2=counter(5),这个时候f1 ==f2吗?
def counter(base): def inc(step=1): nonlocal base base+=step return base return inc f1 = counter(5) f2 = counter(5)
print(f1==f2) print(id(f1)) print(id(f2))
结果为:
False 72178328 40488440
由此可以看到,f1并不等于f2.,它们的ID并不一样,虽然调用的是一个函数,counter参数也是相同的,但是它们的返回值Inc是内部生成的变量,这个Inc有点类似于counter本地变量。而两次调用,变量会生成两次,所以它们的ID不会一样。
现在有这样的一个需求,仿照内建函数sorted,自己来实现一个sort函数,能够为列表的元素排序。
首先,sorted函数会返回一个新的列表,它可以设置升序和降序,那么自定义的函数也需要实现。这个时候应该怎么做么?怎么抽象出这个函数出来。要想抽象出一个函数出来,应该一步步来,首先要想返回一个新的列表,那么需要新建一个列表,然后排序,然后返回。那么这个时候可以先把框架搭好。
def sort(iterable,reverse =False): ret = [] for x in iterable: ret.append(x) return ret
然后就需要把中间的排序代码完善,可以有很多种排序算法。
def sort(iterable,reverse =False): ret = [] for x in iterable: for i,y in enumerate(ret): if x>y:#找到大的就地插入 ret.insert(i,x)#降序 break else:#不大于,说明是最小的,尾部追加。 ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a,reverse=False)) 结果为: [55, 9, 8, 7, 3, 2, 1]
后面还可以变:
def sort(iterable,reverse =False): ret = [] for x in iterable: for i,y in enumerate(ret): flag = x>y if reverse else x<y if flag: ret.insert(i,x) break else: ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a,reverse=True)) 结果为: [55, 9, 8, 7, 3, 2, 1]
上面的就可以反转了。可以将if提成一个函数。
def sort(iterable,reverse =False): def comp(a,b): flag = a>b if reverse else a<b return flag ret = [] for x in iterable: for i,y in enumerate(ret): if comp(x,y): ret.insert(i,x) break else: ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a,reverse=True))
当然也可以把这个函数提出来。
def comp(a,b,reverse): return a>b if reverse else a<b def sort(iterable,reverse =False): ret = [] for x in iterable: for i,y in enumerate(ret): if comp(x,y,reverse): ret.insert(i,x) break else: ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a,reverse=True))
上面的函数还可以这样变形.
def sort(iterable,key = lambda a,b:a>b): ret = [] for x in iterable: for i,y in enumerate(ret): if key(x,y): ret.insert(i,x) break else: ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a))
当然还可以这样变形。
def sort(iterable,reverse = False,key = lambda x,y:x>y): ret = [] for x in iterable: for i,y in enumerate(ret): flag = key(x,y) if not reverse else not key(x,y) if flag: ret.insert(i,x) break else: ret.append(x) return ret a = [1,55,2,7,3,8,9] print(sort(a))
还可以写出很多种。函数的抽象一般都是遵从上面这样的步骤一步步来。
高阶函数——内建函数
sorted,filter,map函数都是属于高阶函数。一个是排序,一个是过滤数据,另一个是映射。
sorted
sorted(iterable[, key][, reverse]) 排序,它返回的是一个新的列表,它是对一个可迭代对象的所有元素进行排序, 排序规则为key定义的函数,reverse表示是否反转。应该注意的是sorted是返回一个新的列表,而sort则是就地修改。同时应该 注意,key并不能修改列表的值,它只是用来比较大小的。
a = [1,55,2,7,3,8,9] print(sorted(a,key = lambda x:6-x)) print(a) print(a.sort(key = lambda x:6-x)) print(a) 结果为: [55, 9, 8, 7, 3, 2, 1] [1, 55, 2, 7, 3, 8, 9] None [55, 9, 8, 7, 3, 2, 1]
filter
filter(function, iterable)它是过滤可迭代对象的元素,返回的是一个迭代器。而function是一个具有一个参数的函数,返回值为boo,filter()函数表示对iterable中的每个元素,都使用function判断,并返回True或者False,最后将返回True的元素组成一个新的可遍历的集合,比如一个列表,过滤出能被4整除的对象。
list(filter(lambda x:x%3==0,[1,9,55,150,-3,78,28,123])) 结果为: [9, 150, -3, 78, 123]
map
map(function, *iterables) --> map object,map函数是对多个可迭代对象的元素按照指定的函数进行映射,然后返回一个迭代器。
list(map(lambda x:2*x+1, range(5))) 结果为: [1, 3, 5, 7, 9] dict(map(lambda x: (x%5,x) , range(500)))#后面的值把前面的值给覆盖了。 结果为: {0: 495, 1: 496, 2: 497, 3: 498, 4: 499}
a = [1,2,3,4,5] new_list = map(lambda x:x*2,a) print(type(new_list)) list(new_list)
结果为:
柯里化Currying
柯里化指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。也就是将z = f(x, y) 转换成 z = f(x)(y)的形式。比如下面的这个函数
def add(x, y): return x + y
将它进行currying就是通过函数嵌套的形式。
def add(x): def _add(y): return x+y return _add add(5)(6) 结果为: 11