python—函数式编程
函数式编程
- 纯函数式编程没有变量,一个函数只要输出确定,输出就是确定的,称为没有副作用.使用变量的函数内部由于变量状态不确定性,有副作用.
- 函数式编程另一个特点是允许函数本身作为参数传入,也可以直接返回另外一个函数.
- python对函数式编程提供有限支持.(还使用变量 so不是纯函数式编程语言)
高阶函数
- python中函数本身也可以赋值给变量,变量可以指向函数
- 函数的参数可以传入另一个函数,这种函数称为高阶函数.
map/reduce
map()接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
示例
1
list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # list所有数字转为字符串
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
示例
1
2
3
4
5
6
7
8
9
10from functools import reduce
def fn(x, y):
return x * 10 + y
...
def char2num(s):
'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} digits = {
return digits[s]
...
map(char2num, '13579')) reduce(fn,
13579
filter
filter()接收一个函数和一个序列。filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
filter()函数返回的是一个 惰性序列 Iterator,也就是一个惰性序列,需要用list()函数获得所有结果并返回list
示例
1
2
3
4
5
6
7
8
9def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 只保留奇数
def not_empty(s):
return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', ' '])) # 删除空字符
sorted
sorted()函数接收一个key函数来实现自定义的排序.第三个参数
reverse=True
决定正序倒序.示例:
1
2
3
4
5sorted(['bob', 'about', 'Zoo', 'Credit'],key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
返回函数
将函数作为结果返回.(很随便😂)
闭包(Closure):相关参数和变量都保存在返回函数.
**note:**返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用
示例(坑):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
f1()
9
f2()
9
f3()
9返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9
一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
示例:
1
2
3
4
5
6
7
8
9def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
匿名函数
不显式定义的函数. python中是
lambda
但与java不同.python中
lambda
限制,只能有一个表达式,不用写return,返回值就是该表达式的结果匿名函数不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
示例
1
f = lambda x: x * x
装饰器
代码运行期间,动态增加功能方式称为装饰器(Decorator)
示例
1
2
3
4
5
6
7
8
9
10
11
12
13def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
def now():
print('2015-3-25')
now()
call now():
2015-3-25如示例,装饰器 接受一个函数作为参数,并返回原函数.在原函数定义时,以
@ xxx
作为标记.示例1 为2层,如果打印文本可以自定义.示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
def now():
print('2015-3-25')
now()
execute now():
2015-3-25打印可自定义 又加上了一层.
如上两种定义后,函数对象的名称等发生了变化,so,终极版
Python内置的functools.wraps 会将原始函数的
__name__
等属性复制到wrapper()函数中.示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import functools
# 不带参数
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
# 带参数
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
偏函数
functools.partial的作用是把一个函数的某些参数设置默认值,返回一个新的函数.
示例:
1
2
3
4import functools
int2 = functools.partial(int, base=2)
int2('1000000')注意: 仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值
由于python 中函数也可以最为参数传入,so,参数固定成某一个函数也可.
同理:
*args
和**kw
也可以.简化函数调用.