函数式编程
特点:允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
python对函数式编程提供部分支持,由于python允许使用变量,因此,python不是纯函数式编程语言。
高阶函数
定义:一个函数可以接受另外一个函数作为参数,就是高阶函数。
python可以写高阶函数:
- 变量可以指向函数
- 函数名也是变量
例如:
1.def add(x,y,f):
2. return f(x)+f(y)
1.>>>add(-5,6,abs)
2.11
map()
定义:map()
函数接收两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
例如:
1.>>> def f(x):
2.... return x * x
3....
4.>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
5.>>> list(r)
6.[1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce()
定义:该函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算。
例如:
1.>>> from functools import reduce
2.>>> def fn(x, y):
3.... return x * 10 + y
4....
5.>>> reduce(fn, [1, 3, 5, 7, 9])
6.13579
举一个同时用map
和reduce
的例子:
1.>>> from functools import reduce
2.>>> def fn(x, y):
3.... return x * 10 + y
4....
5.>>> def char2num(s):
6.... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
7....
8.>>> reduce(fn, map(char2num, '13579'))
9.13579
filter()
定义:fliter()
接收一个函数和一个序列,根据传入函数的返回值是Ture
还是False
决定保留还是丢弃该元素。
例如:
1.def is_odd(n):
2. return n % 2 == 1
3.
4.list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
5.# 结果: [1, 5, 9, 15]
sorted()
定义:key
函数用来实现自定义排序,reverse=True
实现反向排序。
例如:
- 直接进行排序
1.>>> sorted([36, 5, -12, 9, -21])
2.[-21, -12, 5, 9, 36]
- 自定义进行排序
1.>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
2.['about', 'bob', 'Credit', 'Zoo']
- 反向排序
1.>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
2.['Zoo', 'Credit', 'bob', 'about']
返回函数
函数可以作为返回值
- 定例子如下:
1.def lazy_sum(*args):
2. def sum():
3. ax = 0
4. for n in args:
5. ax = ax + n
6. return ax
7. return sum
- 调用时:
1.>>> f = lazy_sum(1, 3, 5, 7, 9)
2.>>> f
3.<function lazy_sum.<locals>.sum at 0x101c6ed90>
4.>>> f()
5.25
- 注意:
当我们调用lazy_sum()
时,每次调用都会返回一个新的函数,即使传入相同的参数
1.>>> f1 = lazy_sum(1, 3, 5, 7, 9)
2.>>> f2 = lazy_sum(1, 3, 5, 7, 9)
3.>>> f1==f2
4.False
闭包
- 定义:当一个函数返回一个函数时,相关的参数和变量都保存在返回的函数中,这种称为“闭包”。
- 注意:返回闭包时,返回函数不要引用任何循环变量,或者后续会发生变化的变量,也就是说,返回函数里面的变量必须在这个函数的任何地方都跟外界的函数没有关系的。
- 错误例子
1.def count():
2. fs = []
3. for i in range(1, 4):
4. def f():
5. return i*i
6. fs.append(f)
7. return fs
8.
9.f1, f2, f3 = count()
·结果
1.>>> f1()
2.9
3.>>> f2()
4.9
5.>>> f3()
6.9
- 改正后:
1.def count():
2. def f(j):
3. def g():
4. return j*j
5. return g
6. fs = []
7. for i in range(1, 4):
8. fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
9. return fs
结果:
1.>>> f1, f2, f3 = count()
2.>>> f1()
3.1
4.>>> f2()
5.4
6.>>> f3()
7.9
匿名函数
- 定义:关键字
lambda
表示匿名函数,冒号前面的x
表示函数的参数
例子:
1.>>>list(map(lambda x:x*x,[1,2,3,4,5,6,7]))
2.[1,4,9,16,25,36,49]
相当于:
1.def f(x):
2. return x*x
- 注意:只能有一个表达式,不用写
return
,返回值就是该式的表达结果。 - 好处:
- 不必担心函数名冲突。
- 匿名函数是一个函数对象,可以把匿名函数赋值给一个变量。
- 匿名函数可以作为返回值返回。
装饰器
函数也是一个对象,函数对象有一个
_name_
属性,可以拿到函数名字
- 定义:在代码运行期间动态增加功能的函数,称为“装饰器”。比如,在函数调用前后自动打印日志,同时又不修改
now()
函数的定义。 - 本质是一个返回函数的高阶函数。所以接受一个函数作为参数,并返回一个函数。
- 使用
例如一个打印日志的decorator
1.def log(func):
2. def wrapper(*args,**kw):
3. print('call %s():' % func._name_)
4. return func(*args,**kw)
5. return wrapper
在使用时,我们要借助Python的@语法,把decorator置于函数的定义处:
1.@log
2.def now():
3. print('2016-8-30')
调用now()
函数,不仅会运行now()
函数本身,还会运行now()
函数前的打印日志函数:
1.>>>now()
2.call now():
3.2016-8-30
这相当于:
1.>>>now=log(now)
- 高级使用
如果decorator本身需要传入参数,比如要自定义log文本:
1.def log(text):
2. def decorator(func):
3. def wrapper(*args, **kw):
4. print('%s %s():' % (text, func.__name__))
5. return func(*args, **kw)
6. return wrapper
7. return decorator
用法:
1.@log('execute')
2.def now():
3. print('2016-8-30')
结果:
1.>>>now()
2.execute now():
3.2016-8-30
相当于:
1.>>>now=log('execute')(now)
首先执行log('execute')
,返回值是decorator
函数,再调用
返回的函数,参数是now
函数,返回值最终是wrapper
函数。
- 注意:
经decorator修饰过的函数,它们的_name_
已经从原来的now
变成了wrapper
了,需要用functools.wraps
把函数名字复制下来。
代码如下:
1.#!/usr/bin/env python3
2. # -*- coding: utf-8 -*-
3.
4.
5.import functools
6.
7.def log(func):
8. #@functools.wraps(func)
9. def wrapper(*args, **kw):
10. print('call %s():' % func.__name__)
11. return func(*args, **kw)
12. return wrapper
13.
14.
15.@log
16.def now():
17. print('2015-3-25')
18.
19.now()
20.print(now.__name__)
21.
22.def logger(text):
23. def decorator(func):
24. @functools.wraps(func)
25. def wrapper(*args, **kw):
26. print('%s %s():' % (text, func.__name__))
27. return func(*args, **kw)
28. return wrapper
29. return decorator
30.
31.@logger('DEBUG')
32.def today():
33. print('2015-3-25')
34.
35.today()
36.print(today.__name__)
运行结果:
1.call now():
2.2015-3-25
3.wrapper
4.DEBUG today():
5.2015-3-25
6.today
偏函数
- 定义:
functools.partial
的作用就是把一个函数的某些参数给固定住(也就是设定默认值),返回一个新的函数,是调用函数变得简单。
例如:
1.def int2(x,base=2):
2. return int(x,base)
调用时:
1.>>>int2('100000')
2.32
用偏函数实现同样的功能:
1.>>> import functools 2.>>> int2 = functools.partial(int, base=2) 3.>>> int2('1000000') 4.64 5.>>> int2('1010101') 6.85