1.python中的函数式编程
函数式编程的特点
- 把计算视为函数而非指令
- 纯函数式编程,不需要变量,没有副作用,测试简单
- 支持高阶函数,代码简洁
- 不是纯函数式编码:允许有变量
- 支持高阶函数:函数也可以作为变量传入
- 支持闭包:有了闭包就能返回函数
- 有限度地支持匿名函数
2.python的高阶函数
函数名可以作为变量,如
- 变量可以是指向函数
- 函数的参数可以接收变量
- 一个函数可以接收另一个函数作为参数
- 能接收函数作为参数的函数就是高阶函数
1 #函数作为参数示例 2 def add(x,y,f): 3 return f(x)+f(y) 4 add(-5,9,abs)
结果为 14
3.python将函数作为参数
在第1节中,我们讲了高阶函数的概念,并编写了一个简单的高阶函数:def add(x, y, f):
return f(x) + f(y)
如果传入abs作为参数f的值:
add(-5, 9, abs)
根据函数的定义,函数执行的代码实际上是:
abs(-5) + abs(9)
由于参数 x, y 和 f 都可以任意传入,如果 f 传入其他函数,就可以得到不同的返回值。
示例,利用add(x,y,f)函数,计算
-
1 import math 2 def add(x, y, f): 3 return f(x)+ f(y) 4 print(add(25,9, math.sqrt))
4.python中的map函数
1 def f(x): 2 return x*x 3 print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
输出结果:
1 def format_name(s): 2 a = s[0].upper() 3 b = s[1:].lower() 4 return a+b 5 print(list(map(format_name,['adam','LISA','barT'])))
5. python中reduce函数
任务
Python内置了求和函数sum(),但没有求积的函数,请利用recude()来求积:
输入:[2, 4, 5, 7, 12]
输出:2*4*5*7*12的结果
1 from functools import reduce 2 def prod(x, y): 3 return x*y 4 5 print(reduce(prod,[2,4,5,7,12]))
6. python中的filter()函数
filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
任务
请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
1 import math 2 def is_sqr(x): 3 a = math.sqrt(x)%1 4 if a ==0.0: 5 return True 6 else: 7 return False 8 9 l = filter(is_sqr, range(1,101)) 10 print(list(l))
7. python中自定义排序函数
任务
对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。
输入:['bob', 'about', 'Zoo', 'Credit']
输出:['about', 'bob', 'Credit', 'Zoo']
1 #-*- coding=utf8 -*- 2 #这段代码在Python2.7可以运行,python3.x之后sorted函数不支持自定义比较函数,在python3.x中sorted函数的定义为 3 #sorted(iterable, /, *, key=None, reverse=False) 4 #可以通过将reverse参数设置为True来实现上面的功能 5 6 def cmp_ignore_case(s1, s2): 7 if s1.lower()> s2.lower(): 8 return 1 9 elif s1.lower()< s2.lower(): 10 return -1 11 else: 12 return 0 13 14 print sorted(['bob','about','Zoo','Credit'], cmp_ignore_case)
8. python中的返回函数
Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!
例如,定义一个函数 f(),我们让它返回一个函数 g,可以这样写:
def f(): print 'call f()...' # 定义函数g: def g(): print 'call g()...' # 返回函数g: return g
仔细观察上面的函数定义,我们在函数 f 内部又定义了一个函数 g。由于函数 g 也是一个对象,函数名 g 就是指向函数 g 的变量,所以,最外层函数 f 可以返回变量 g,也就是函数 g 本身。
调用函数 f,我们会得到 f 返回的一个函数:
>>> x = f() # 调用f() call f()... >>> x # 变量x是f()返回的函数: <function g at 0x1037bf320> >>> x() # x指向函数,因此可以调用 call g()... # 调用x()就是执行g()函数定义的代码
请注意区分返回函数和返回值:
def myabs(): return abs # 返回函数 def myabs2(x): return abs(x) # 返回函数调用的结果,返回值是一个数值
返回函数可以把一些计算延迟执行。例如,如果定义一个普通的求和函数:
def calc_sum(lst): return sum(lst)
调用calc_sum()函数时,将立刻计算并得到结果:
任务
请编写一个函数calc_prod(lst),它接收一个list,返回一个函数,返回函数可以计算参数的乘积。
1 #python2.7 2 def calc_prod(lst): 3 def f(): 4 return reduce(lambda x,y:x*y,lst) 5 return f 6 7 f = calc_prod([1,2,3,4]) 8 print f()
9. python中的闭包
在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问:
def g(): print 'g()...' def f(): print 'f()...' return g
将 g 的定义移入函数 f 内部,防止其他代码调用 g:
def f(): print 'f()...' def g(): print 'g()...' return g
但是,考察上一小节定义的 calc_sum 函数:
def calc_sum(lst): def lazy_sum(): return sum(lst) return lazy_sum
注意: 发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 lst。
像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:
# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:
>>> f1()
9 # 因为f1现在才计算i*i,但现在i的值已经变为3
因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
任务
返回闭包不能引用循环变量,请改写count()函数,让它正确返回能计算1x1、2x2、3x3的函数。
1 #python 2.7 2 def count(): 3 fs =[] 4 for i in range(1,4): 5 def f(m=i): 6 return m*m 7 fs.append(f) 8 return fs 9 10 f1, f2, f3 = count() 11 print f1(), f2(), f3()
10. python中的匿名函数
高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。
利用匿名函数简化以下代码:
1 def is_not_empty(s): 2 return s and len(s.strip()) > 0 3 filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])
#python 2.7 print filter(lambda s: s and len(s.strip())>0, ['test',None,'','str',' ','END'])
11. python中的装饰器
def f1(x): return x*2 def f2(x): return x*x def f3(x): return x*x*x
希望在不修改函数的代码,在函数调用时打印出log
def f1(x): return x*2 def new_fn(f):#装饰器函数 def fn(x): print 'call' + f.__name__+'()' return f(x) return fn
12. python中编写无参数的decorator
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
任务
请编写一个@performance,它可以打印出函数调用的时间。
1 #python 2.7 2 import time 3 def performance(f): 4 def fn(*args,**kw): 5 print'call '+ f.__name__ +'() in '+ time.strftime('%Y-%m-%d %X', time.localtime()) 6 return f(*args,**kw) 7 return fn 8 9 @performance 10 def factorial(n): 11 return reduce(lambda x,y: x*y, range(1, n+1)) 12 13 print factorial(10)
13. python中编写带参数的装饰器
任务
上一节的@performance只能打印秒,请给 @performace 增加一个参数,允许传入's'或'ms':
@performance('ms') def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1))
1 #python 2.7 2 import time 3 def performance(prefix): 4 def performance1(f): 5 def fn(*args,**kw): 6 start = time.clock() 7 time.sleep(1) 8 ret = f(*args,**kw) 9 end = time.clock() 10 if prefix =='s': 11 print('call '+ f.__name__+"() used " + str((end-start)) +'s') 12 else: 13 print('call '+ f.__name__+"() used " + str((end-start)*1000) + 'ms') 14 return ret 15 return fn 16 return performance1 17 18 @performance('ms') 19 def factorial(n): 20 return reduce(lambda x,y: x*y, range(1, n+1)) 21 22 print(factorial(10))
14. python中完善decorator
任务
请思考带参数的@decorator,@functools.wraps应该放置在哪:
def performance(unit): def perf_decorator(f): def wrapper(*args, **kw): ??? return wrapper return perf_decorator
1 import time, functools 2 def performance(prefix): 3 def performance1(f): 4 @functools.wraps(f) 5 def fn(*args,**kw): 6 start = time.clock() 7 time.sleep(1) 8 ret = f(*args,**kw) 9 end = time.clock() 10 if prefix =='s': 11 print('call '+f.__name__+"() used ",(end-start),'s') 12 else: 13 print('call '+f.__name__+"() used ",(end-start)*1000,'ms') 14 return ret 15 return fn 16 return performance1 17 18 @performance('ms') 19 def factorial(n): 20 return reduce(lambda x,y: x*y, range(1, n+1)) 21 22 print(factorial.__name__)
15. python中的偏函数
任务
在第7节中,我们在sorted这个高阶函数中传入自定义排序函数就可以实现忽略大小写排序。请用functools.partial把这个复杂调用变成一个简单的函数:
sorted_ignore_case(iterable)
1 import functools 2 def f(x): 3 return x.lower() 4 5 sorted_ignore_case = functools.partial(sorted,key=f) 6 print(sorted_ignore_case(['bob','about','Zoo','Credit']))