函数式编程(FunctionalProgramming)
-
基于lambda演算的一种编程方式
- 程序中只有函数
- 函数可以作为参数,同样可以作为返回值
- 纯函数式编程语言: LISP, Haskell
-
Python函数式编程只是借鉴函数式编程的一些特点,可以理解成一半函数式一半Python
- 需要讲述
- 高阶函数
- 返回函数
- 匿名函数
- 装饰器
- 偏函数
高阶函数(Higher-order function)
- 把函数作为参数使用的函数,叫高阶函数
# 变量可以赋值
a = 100
b = a
# 函数名称就是一个变量
def funA():
print("In funA")
funB = funA
funB()
In funA
以上代码得出的结论:
- 函数名称是变量
- funB 和 funA只是名称不一样而已
- 既然函数名称是变量,则应该可以被当做参数传入另一个函数
# 高阶函数举例
# funA是普通函数,返回一个传入数字的100倍数字
def funA(n):
return n * 100
# 再写一个函数,把传入参数乘以300倍,
def funB(n ):
# 最终是想返回300n
return funA(n) * 3
print(funB(9))
# 写一个高阶函数
def funC(n, f):
# 假定函数是把n扩大100被
return f(n) * 3
print( funC(9, funA) )
# 比较funC和funB, 显然funC的写法要优于funB
# 例如:
def funD(n):
return n*10
# 需求变更,需要把n放大三十倍,此时funB则无法实现
print(funC(7, funD))
2700 2700 210
如果你读过Google的那篇大名鼎鼎的论文“MapReduce: Simplified Data Processing on Large Clusters”,你就能大概明白map/reduce的概念。
我们先看map。
map()
函数接收两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]
上,就可以用map()
实现如下:
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
map()
作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:
>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce
- 原意是归并,缩减
- 把一个可迭代对象最后归并成一个结果
- 对于作为参数的函数要求: 必须由两个参数,必须由返回结果
- reduce([1,2,3,4,5]) == f( f(f(f(1,2),3), 4),5)
- reduce 需要导入functools包
from functools import reduce
# 定义一个操作函数
# 加入操作函数只是相加
def myAdd(x,y):
return x + y
# 对于列表[1,2,3,4,5,6]执行myAdd的reduce操作
rst = reduce( myAdd, [1,2,3,4,5,6] )
print(rst)
21
把序列[1, 3, 5, 7, 9]
变换成整数13579
,reduce
就可以派上用场
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579
filter 函数
- 过滤函数: 对一组数据进行过滤,符合条件的数据会生成一个新的列表并返回
- 跟map相比较:
- 相同:都对列表的每一个元素逐一进行操作
- 不同:
- map会生成一个跟原来数据想对应的新队列
- filter不一定,只要符合条件的才会进入新的数据集合
- filter函数怎么写:
- 利用给定函数进行判断
- 返回值一定是个布尔值
- 调用格式: filter(f, data), f是过滤函数, data是数据
# filter案例
# 对于一个列表,对其进行过滤,偶数组成一个新列表
# 需要定义过滤函数
# 过滤函数要求有输入,返回布尔值
def isEven(a):
return a % 2 == 0
l = [3,4,56,3,2,3,4556,67,4,4,3,23455,43]
rst = filter(isEven, l)
# 返回的filter内容是一个可迭代对象
print(type(rst))
print(rst)
print([i for i in rst])
<class 'filter'> <filter object at 0x7f503403df60> [4, 56, 2, 4556, 4, 4]
高阶函数-排序sorted
排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。
- 把一个序列按照给定算法进行排序
- key: 在排序前对每一个元素进行key函数运算,可以理解成按照key函数定义的逻辑进行排序
- python2 和 python3 相差巨大
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
a = [-43,23,45,6,-23,2,-4345]
# 按照绝对值进行排序
# abs是求绝对值的意思
# 即按照绝对值的倒叙排列
al = sorted(a, key=abs, reverse=True)
print(al)
[-4345, 45, -43, 23, -23, 6, 2]
# sorted案例
astr = ['dana', 'Danaa', 'wangxiaojing', 'jingjing', 'haha']
str1 = sorted(astr)
print(str1)
str2 = sorted(astr, key=str.lower)
print(str2)
['Danaa', 'dana', 'haha', 'jingjing', 'wangxiaojing'] ['dana', 'Danaa', 'haha', 'jingjing', 'wangxiaojing']