函数式编程
高阶函数
map, filter, sorted
递归 recursion
闭包 closure
函数式编程
函数式编程
函数式编程是指用一系列函数解决问题
好处:
1.用每一个函数完成细小的功能, 一系列函数的任意组合可以完成大问题
2.函数仅接受输入并产生输出, 不包含任何能影响输出的内部状态
函数是一等公民(Guido)
1.函数本身可以赋值给变量,赋值后变量绑定函数
2.允许将函数本身作为参数传入另一个函数
3.允许函数返回一个函数
函数的可重入性
如果一个函数的输入参数一定, 则返回结果必须一定的函数称为可重入函数
例
#可冲入函数,传入函数一定,结果必然一定
def myadd(x, y):
return x+y
#不可重入函数
y =200
def myaddd#引用了外部变量, 变成不可重函数
return x + y
print(myadd(10))
函数编程的要求:
def创建的函数最好不要访问局部作用域以外的变量,这样可以保证返回结果的唯一性(可重入性)
测试 调试
s = sum(range(1, 101))
1~100的和
例:
可重入函数:
def add1(x,y) # 尽量用可重入函数
return x+y
add1(100,200)
不可重入函数
y=200 # 引用了外部变量 变成不可重入函数
def add2(x):
return x+y
print(add2(10)) # 210
y=300
print(add2(10)) #310
高阶函数
High Order Function
指满足下列条件之一的即为高阶函数
1.函数接受一个或多个函数作为参数传入
2.函数返回一个函数
>>> def fx(fn, L):
... return fn(L)
...
>>> fx(sum, [1, 2, 3, 4])
10
>>> fx(100, 200)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fx
TypeError: 'int' object is not callable
>>> def fy():
... def hello():
... print("hello world")
... return hello#加括号不是返回函数, 而是调用后的返回结果
python内建函数的高阶函数
map, filter, sorted
高阶函数 High Order Function
函数说明作用
map(func, *iterables) 用函数和对可迭代对象中的每一个元素作为参数计算出新的可迭代对象,当最短的一个可迭代对象不再提供数据时此可迭代对象生成结束
filter(function, iterable) 过滤
筛选可迭代对象iterable中的数据,返回一个可迭代器对象,此可迭代对象将对iterable进行筛选.函数function 将对iterable中的每个元素进行求值,返回False则将此数据丢弃,返回True,则保留此数据
sorted(iterable, key=None, reverse=False) 将原可迭代对象的数据进行排序,生成排序后的列表iterable 可迭代对象
key 函数是用来提供一个值,这个值将作为排序的依据reverse 标志用来设置是否降序排序
map函数
格式
map(func,*iterables)
*iterables星号元组形参
=def map(fn, *args):
...
用函数和对可迭代对象中的每一个元素作为参数返回新的可迭代对象,当最短的一个可迭代对象不再提供数据是迭代结束
要求:
func函数接收的参数个数必须与可迭代对象的个数相同
例:
1 # 生成一个可迭代对象, 此可迭代对象可以生成1~9自然数的平方#1 4 9 16 。。。81 2 3 L = [] 4 a = int(input('请输入:')) 5 def power2(x): 6 return x**2 7 8 for x in map(power2, range(1, a+1)): 9 L.append(x) 10 print(L)
1 # 生成1**3 2**3 3**3 2 def power3(x): 3 return x**3 4 5 for x in map(power3, range(1, 10)): 6 print(x)
for x in map(lambda x: x**4, range(1, 10)): print(x)
练习
用map函数1**3+2**3+3**3+.....9**3的和
用map函数1**4+2**4+3**4+....20**4的和
用sum(map(....))
1 print(sum(map(lambda x : x**3, range(1, 10)))) 2 3 s = 0 4 for x in range(1, 10): 5 s += x**3 6 print('和是:', s) 7 8 s = 0 9 for x in map(lambda x : x**3, range(1, 10)): 10 s += x 11 print('和是:', s) 12 13 14 s = sum(map(lambda x : x**3, range(1, 10))) 15 print('和是:', s)
1 def power20(x): 2 return x**4 3 print(sum(map(power20, range(1, 21))))
说明:
>>> pow(1, 9)
1#1**9
>>> pow(2, 3)
8#2**3
1 #生成可迭代对象 2 # 1**4, 2**3, 3**2, 4**1 3 def pow_a_b(a, b): 4 return a ** b 5 6 for x in map(power_a_b, 7 [1, 2, 3, 4], #可加5, 6, 7, 8 8 [4, 3, 2, 1]) 9 print(x) 10 11 12 def power_a_b(a,b): 13 return a ** b 14 for x in map(power_a_b, 15 [1,2,3,4,5,6,7,8], # 按最短的可迭代对象 16 [4,3,2,1]): 17 print(x) 18 19 L=list(map(pow,range(1,10),range(9,0,-1))) 20 print(L) # 生成列表 21 22 def k_v(a,b): 23 return (a,b) 24 d=dict(map(k_v,range(1,10),range(9,0,-1))) 25 print(d) # 生成字典
filter函数
filter(function, iterable)
1 # filter 函数示例 2 # 写一个函数,判断x 是否为奇数,奇数返回True ,偶数返回False 3 4 def is_odd(x): 5 if x % 2 == 1: 6 return True 7 return False
例:
写一个函数判断是否为奇数
1 def is_odd(x): 2 if x % 2 == 1: 3 return True 4 return False
返回可迭代对象
range(..)
map(..)
filter(..)
reversed(..)
1 # 求1**9+2**8+3**7....9**1 2 3 def isodd(x): 4 return x % 2 == 1 5 for x in filter(isodd, range(41, 53)): 6 print(x) 7 8 s = 0 9 for x in map (pow, range(1, 10), range(9, 0, -1)): 10 s +=x 11 print(x) 12 print(s) 13 14 15 # 终端运行 16 >>> s = 0 17 >>> for x in map (pow, range(1, 10), range(9, 0, -1)): 18 ... s +=x 19 ... print(x) 20 ... 21 # 1 22 # 256 23 # 2187 24 # 4096 25 # 3125 26 # 1296 27 # 343 28 # 64 29 # 9 30 # >>> s 31 # 11377
>>> list(map (pow, range(1, 10), range(9, 0, -1)))
[1, 256, 2187, 4096, 3125, 1296, 343, 64, 9]
生成1~10以内的奇数列表#[1, 3 5 7 9]
1 for x in filter(is_odd, range(1, 10)): 2 print(x) 3 4 L = [x for x in filter(is_odd, range(1, 10))] 5 print(L)#[1, 3, 5, 7, 9]
sorted函数
作用:
将原可迭代对象提供的数据进行排序,生成排序后的列表
格式:
sorted(iterable,key=None,reverse=False)
说明:
iterablek 可迭代对象
key 函数是用来提供一个排序参考值的函数,这个函数的返回值将作为
排序的依据
reverse 标志用来设置是否降序排序
示例:
L = [5,-2,-4,0,3,1]
L2 = sorted(L) # [-4,-2,0,1,3,5]
# 要得到这样的结果该怎么办?
#[0,1,-2,3,-4,5]
L3 = sorted(L,key=abs)
names = ['Tom','Jerry','Spike','Tyke']
#结果['Tom','Tyke','Jerry','Spike']
L = sorted(name) # 按名字首字母排序
L = sorted(name,key=len) # 按名字长短
练习:
已知:
names = ['Tome','Jerry','Spike','Tyke']
排序的依据为原字符串反序的字符串
names = ['Tom','Jerry','Spike','Tyke']
def get_key(n):
'''n用来绑定参数中每个元素,n绑定名字(字符串)
此函数需要返回一个能比较大小的依据'''
return n[::-1]
L=sorted(names,key=get_key)
print(L)
结果['Spike', 'Tyke', 'Tom', 'Jerry']
fangfa2
L=sorted(names,key=lambda n:n[::-1])
print(L)
1 names = ["Tom", 'Jerry', 'Spike', 'Tyke'] 2 L1 = sorted(names, key=lambda x : x[::-1])#有双::是顺序翻过, 无冒号则最后一个字母 3 print(L1) 4 ['Spike', 'Tyke', 'Tom', 'Jerry'] 5 6 7 names = ["Tom", 'Jerry', 'Spike', 'Tyke'] 8 def k(s): 9 return s[::-1] 10 11 L = sorted(names, key = k) 12 print(L)
练习:
1.将1~20 的偶数用filter 生成可迭代对象后将可迭代对象生成的数
放入到列表 L中
2.写一个函数 is_prime(x),判断x 是否是素数,用 函数打印出:
20~30 之间的全部素数
1 # sorted.py 2 3 L = [5, -2, -4, 0, 3, 1] 4 L2 = sorted(L)#L = [-4, -2, 0, 1, 3, 5] 5 L3 = sorted(L, reverse=True)#L = [-4, -2, 0, 1, 3, 5]降序排序 6 7 L4 = sorted(L, key=abs) 8 #L4 = [0, 1, -2, 3, -4, 5] 9 print(L4) 10 L5 = sorted(L, key=abs, reverse=True) 11 print(L5)#[5, -4, 3, -2, 1, 0] 12 13 # "abs"去绝对值 14 15 16 17 # sorted2.py 18 19 names = ["Tom", 'Jerry', 'Spike', 'Tyke'] 20 21 L1 = sorted(names) 22 print('L1', L1) 23 # L1 ['Jerry', 'Spike', 'Tom', 'Tyke'] 24 25 L2 = sorted(names, key=len) 26 print("L2", L2) 27 # L2 ['Tom', 'Tyke', 'Jerry', 'Spike'] 28 29 L3 = sorted(names, key=lambda x : len(x)) 30 # print("L3", L3) 31 L3 ['Tom', 'Tyke', 'Jerry', 'Spike']
递归函数recursion
函数直接或间接的调用函数自身
>>> def story():
... print("congqianyouzuosan, 山上有座庙。。。")
... story()
...
>>>
>>> story()
递归的事例
函数直接调用自己
def f():
f()#调用自己
f()
#函数间接的调用自己
def fa():
fb()
def fb():
fa()
fa()
print("递归完成")
递归说明:
递归一定要控制递归的层数, 当符合一定条件时要终止递归几乎所有的递归都能用while循环来代替
优缺点
优点:
递归吧问题简单化, 让思路更为清晰, 代码更简洁
缺点:
递归因系统环境影响大, 当递归深度太大时, 可能回得到不可预知的结果
递归的两个阶段:
递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归的 终止条件
回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到问题 求解
示例:
1 def fn(n): 2 print("递归进入第",n,'层') 3 if n == 3: # 当递归进入第三层时,将不再向下走,开始回归 4 return 5 fn(n+1) 6 print("递归退出第",n,'层') 7 8 fn(1) 9 print("程序结束")
示例:
写一个函数求n的阶乘(递归实现)
# 1*2*3*4*5等同于5*4*3*2*1
# 5!=5*4!...2!=2*1!
1 def myfac(n): 2 if n==1: 3 return 1 4 return n *myfac(n-1) 5 6 print("5的阶乘是:",myfac(5))
递归的实现方法:
先假设函数已经实现
写一个函数mysum(n),用递归方法求
1+2+3+4+....+n的和
1 def mysum(n): 2 if n ==1: 3 return 1 4 return n+mysum(n-1) 5 6 print(mysum(100))
例:
1 # recursion.py 2 3 def fx(n): 4 print("fx进入第", n, '层') 5 # fx(n+1) 6 print("fx退出第", n, '层') 7 8 9 fx(1) 10 print("程序结束") 11 12 13 # fx进入第 1 层 14 # fx进入第 2 层 15 # fx进入第 3 层 16 # fx进入第 4 层 17 # fx进入第 5 层 18 # fx进入第 6 层 19 20 21 # fx进入第 995 层 22 # fx进入第 996 层 23 # fx进入第 997 层 24 25 26 27 28 29 def fx(n): 30 print("fx进入第", n, '层') 31 if n == 3: 32 return 33 fx(n+1) 34 print("fx退出第", n, '层') 35 36 37 fx(1) 38 print("程序结束") 39 40 # fx进入第 1 层 41 # fx进入第 2 层 42 # fx进入第 3 层 43 # fx退出第 2 层 44 # fx退出第 1 层 45 # 程序结束
1 # 1.给出一个整数n,写一个函数来计算n!(n的阶乘) 2 # n! = 1*2*3*.....* n 3 4 # n!=n*(n-1)*(n-2)*...3*2*1 5 # 100!=100*99*98...3*2*1 6 7 def fac(n): 8 if n == 1:#当1!直接返回1 9 return 1 10 return n*fac(n-1) 11 12 print(fac(5)) 13 # 120 14 15 def fac(n): 16 return n*(n-1) 17 print(fac(5)) 18 19 # 20
递归练习:
用递归方式实现求和 mysum(n)
1 def mysum(n): 2 if n ==1: 3 return 1 4 return n + mysum(n-1) 5 6 print(mysum(100)) 7 8 9 s = 0 10 for i in range(1, 101): 11 s +=i 12 print (s) 13 14 15 print(sum(x for x in range(1, 101))) 16 17 18 print(sum(map(lambda x : x, range(1, 101))))
1 def friend(n): 2 if n == 1: 3 return 10 4 return friend(n-1)+2 5 6 print(friend(5))
闭包closure
闭包是指引用此函数外部的变量的函数
说明:
在本质上, 闭包是将内部嵌套函数和函数外部的执行环境绑定在一起的对象
闭包
闭包必须满足三个条件
1.必须有一个内嵌函数
2.内嵌函数必须引用外部函数中的变量
3.外部函数返回值必须是内嵌函数
1 # closure.py 2 # 闭包示例: 3 def make_power(y): 4 def fn(arg): 5 return arg ** y 6 return fn 7 8 9 pow2 = make_power(2) # 请问pow2绑定的是什么? 10 print('5的平方是:', pow2(5)) 11 12 # 求1**2 + 2 ** 2 + 3 ** 2 + .... 100 ** 2 13 print(sum(map(lambda x: x ** 2, range(1, 101)))) 14 print(sum(map(make_power(2), range(1, 101)))) 15 16 print("1 ** 3 + 2**3 + ...... + 100 ** 3=") 17 print(sum(map(lambda x: x ** 3, range(1, 101)))) 18 print(sum(map(make_power(3), range(1, 101)))) 19 # print(sum(map(lambda x: x ** 3, range(1, 101))))
求1**2+2***2+3**2+...100**2
1 print(sum(map(lambda x : x ** 2, range(1, 101)))) 2 3 def make_power(y): 4 def fn(arg): 5 return arg ** y 6 return fn 7 8 print(sum(map(make_power(2), range(1, 101)))) 9 10 11 1**3+2***3+3**3+...100**3 12 13 print(sum(map(lambda x : x ** 3, range(1, 101))) 14 15 16 def make_power(y): 17 def fn(arg): 18 return arg ** y 19 return fn 20 21 print(sum(map(make_power(3), range(1, 101))))
例:
用闭包来创建函数
示例:
1 f(x) = a*x**2 + b*x + c 2 3 def get_fx(a, b, c): 4 def fx(x): 5 return a * x ** 2 + b * x + c 6 return fx 7 8 f123 = get_fx(1, 2, 3) 9 print(f123(20)) 10 print(f123(50)) 11 12 f654 = get_fx(6, 5, 4) 13 print(f654(30))
闭包示例:
def make_power(y): def fn(x): return x **y return fn pow2=make_power(2) # pow2绑定的是什么? print("5的平方是",pow2(5)) pow3=make_power(3) print("6的立方是",pow3(6))
闭包的实例应用:
用闭包来创建任意的f(x)=a * x ** 2 +b * x ** 1 + c的函数
1 def get_fx(a,b,c): 2 def fx(x): 3 return a * x ** 2 + b * x ** 1 + c 4 return fx 5 6 #创建函数f(x)=1 * x** 2 + 2 * x ** 1+ 3 7 f123=get_fx(1,2,3) 8 print(f123(20)) # 443 9 print(f123(50)) # 2603 10 11 f654=get_fx(6,5,4) 12 print(f654(10)) # 654 13 print(f654(30)) # 5554
练习:
1.已知:
第五个人比第四个人大2岁
第四个人比第三个人大2岁
第三个人比第二个人大2岁
第二个人比第一个人大2岁
第一个人说他10岁
编写程序算出第五个人几岁
(思考是否可以使用递归和循环两种方法来做)
1 fangfa1 递归 2 def get_age(a): 3 '''此函数返回第n个人多少岁''' 4 if n ==1: 5 return 10 6 return get_age(n-1)+2 7 print("第五个人%d岁" % get_age(5)) 8 9 fangfa2 循环 10 def get_age(n): 11 age=10 12 for x in range(2,n+1): 13 age += 2 14 return age 15 print("第五个人%d岁" % get_age(5))
1 def pengyou(n): 2 if n == 1: 3 return 10 4 return pengyou(n-1) + 2 5 6 print(pengyou(5)) 7 print(pengyou(3))
2.已知有列表:
L=[[3,5,8],10,[[13,14],15,18],20]
1)写一个函数print_list(lst)打印出列表内的所有元素
print_list(L) # 3,5,8,10,13..
2)写一个函数sum_list(lst):
返回这个列表中所有元素的和
print(sum_list(L)) # 86
注:type(x)可以返回一个变量的类型
如:
>>>type(20) is int # True
>>>type([3,5,8]) is list # True
1)
1 1) 2 L=[[3,5,8],10,[[13,14],15,18],20] 3 def print_list(lst): 4 for x in lst: 5 if type(x) is int: 6 print(x,end=' ') 7 else: 8 print_list(x) 9 # 递归调用处理内部列表 10 print_list(L) 11 print()
2)
1 def sum_list(lst): 2 s=0 # 用于累加lst中的所有数的和 3 for x in lst: 4 if type(x) is int: 5 s += x 6 else: 7 s += sum_list(x) 8 return s # 返回当前的lst的结果 9 10 print(sum_list(L))
1 L = [[3,5,8],10,[[13,14],15,18],20] 2 3 def print_list(lst): 4 for x in lst: 5 if type(x) is int: 6 print(x,end= ' ') 7 elif type(x) is list: 8 print_list(x) 9 10 print_list(L)
1 def sum_list(lst): 2 s = 0 3 for x in lst: 4 if type(x) is int: 5 s += x 6 elif type(x) is list: 7 s += sum_list(x) 8 return s 9 10 print(sum_list(L))
3.改写之前的学生信息管理程序
要求添加四个功能:
|5)按学生成绩高-低显示学生信息|
|6)按学生成绩低-高显示学生信息|
|7)按学生年龄高-低显示学生信息|
|8)按学生成绩低-高显示学生信息|