十、函数式编程:匿名函数、高阶函数、装饰器

10 函数式编程:匿名函数、高阶函数、装饰器

10.1 lambda表达式与三元表达式

1
2
3
4
5
6
7
8
9
10
11
12
# 匿名函数
# lambda parameter_list: expression
# lambda 参数列表: 表达式
f = lambda x,y: x+y
#此处的expression只能是简单的B表达式,而不能实现像函数内部的代码块。
print(f(1,9)) # 10

x = 1
y = 2
# 条件为真时的返回结果 if 条件判断 else 条件为假时的返回结果
r = x if x > y else y
print(r) # 2

10.2 map与lambda

map:
a.不推荐在业务代码中大量使用闭包,如果是框架、包、类库则可以尝试使用;
b. map 返回是啊object map对象,可根据需要进行相应的转化:

求一个list所有元素平方后的list:

1
2
3
4
5
6
7
8
def squ(x):
return x*x

a = [1,2,3,4]
s = map(squ,a)
print(type(s))# <class 'map'>
print(s) # <map object at 0x007A11F0>
print(list(s)) # [1, 4, 9, 16]

由lambda改进后:

1
2
3
4
5
6
7
8
9
10
a = [1,3,9,10]
b = [1,3,9]
aa = map(lambda x: x*x , a)
print(list(aa))#[1, 9, 81, 100]

#map可以和lambda表达式结合,而且可以接收多个参数。
# 其中若有多个集合参数则长度最好一样,
# 如果不一样,map会按照长度最小的计算
ab = map(lambda x,y: x*x+y, a,b)
print(list(ab))#[2, 12, 90]

10.3 reduce

a. python3中reduce已经不在全局命名空间里了,因此要使用reduce必须导入,如from functools import reduce ;
说明:reduce用于连续计算,即reduce的第一个函数参数必须至少有两个参数;
b. reduce函数格式:
reduce(function, sequence, initial = None);
注:此处的初始值initial是在第一次计算时作为初始值来计算的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
w4.py
from functools import reduce
# reduce
s = ['1','2','a','kitty']

#def reduce(function, sequence(序列), initial)
# reduce 连续做运算,连续调用 lambda
rs = reduce(lambda x,y: x+y, s,'100') # 先对 100 进行运算
print(rs) #10012akitty

# map/reduce 编程模式:映射、归约,并行运算
# 函数式编程思想

#reduce应用于求x-y坐标的点
pos = [(1,2),(3,4),(4,-7),(-9,0)]
new_pos = reduce(lambda x,y: x+y, pos,(0,0))
# 相加失败...后续再改一下???
print(new_pos)

10.4 filter

Filter 过滤掉一些不需要或者不符合规则的元素;
其中的参数–函数:返回结果一定为True 或 False,要么等价于True或False,真不过滤 假过滤;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 过滤掉 0 
a = [1,2,0,3,0,3,0,6,0]
# filter 根据函数返回的结果的真假来进行过滤
ra = filter(lambda x: True if x != 0 else False, a)
print(list(ra)) #[1, 2, 3, 3, 6]

# 过滤掉大写字母
zm = ['a','b','S','k','D']
rz = filter(lambda x: True if 'a'<=x<='z' else False,zm)
print(list(rz)) # ['a', 'b', 'k']

# print(ord('a')) # 97
# print(ord('z')) #122
# print(ord('A'))# 65
# print(ord('Z'))# 90

小结:命令式编程与函数式编程

理论可以用map reduce filter(常见命令式编程)加 lambda 算子替换所有命令式编程(def if else for)的复杂逻辑;命令式编程结合函数式编程写出简介的代码;lisp是函数式编程的鼻祖,人工智能领域用的比较多。

10.4 装饰器

a.装饰器所要解决的问题:在不修改原始代码逻辑的情况下,增加函数的功能;
b.装饰器可以满足:对修改是封闭的,对扩展是开放的。

10.4.1 了解装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
"""  
给每个函数增加打印当前时间的功能
"""
import time
# 实现方案一
def f1():
#print(time.time())
print('f1')
f1()

# 实现方案 2 关联性不好
print('=== 实现方案 2 ===')
def print_curr_time(fun):
print(time.time())
fun()
print_curr_time(f1)

# 实现方案三(关联性依旧不好)
# 只是封装到了函数内部,内聚性更高一些
print('===方案三===')
def decorator(fun):
def wrapper():
print(time.time())
fun()
return wrapper
f = decorator(f1)
f()

#方案四(语法糖),AOP编程思想
# 语法糖\装饰器 调用
print('===方案四、语法糖调用')
@decorator
def f3():
print('f3')
f3()
10.4.2 熟悉装饰器

function(*args, **kw)形式的函数可以传入任意参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 参数优化后的装饰器
import time
#可变参数、关键字参数---万能接收参数?
def curr_time_print(fun):
def add_fun(*funts, **kw):
print(time.time())
fun(*funts,**kw) # kw在函数中当作字典打印出来
return add_fun

@curr_time_print
def china_time():
print('东八')

@curr_time_print
def america_time(dollar,movie):
print('movie: '+movie + '\n'+'price: '+dollar)

@curr_time_print
def korea(movie, bua, **byl):
print(movie+' '+bua)
print(byl)

china_time()
print('====america=======')
america_time('30$','happy for you')
print('===korea===')
korea('shuangluohua','pujinna',a = 1,b = 2 ,c = '1,2')
#1530854256.264747
# shuangluohua pujinna
# {'a': 1, 'b': 2, 'c': '1,2'}

小结:
1.可以再不改变函数的情况下通过装饰器来给函数增加功能;
2.方便且一个函数可以有多个装饰器

分享到