Python学习笔记–3.函数式编程
MrZigZag@Peking University
2015-07-12
1.函数式编程
抽象层次比较高,允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
Python对函数式编程提供部分支持。
2.高阶函数
将简单的函数作为参数传入高阶函数。
def add(x, y, f):
return f(x) + f(y)
>>> add(-5, 6, abs)
11
map()
接收两个参数,一个是函数另一个是序列,返回一个经函数处理过的序列。
def f(x):
return x * x
>>> map(f, range(1,10))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce()
是把一个函数f作用在一个序列list上,函数f接收两个参数,因而是逐个累积运算。
reduce(f, [1, 2, 3]) = f(f(1, 2), 3)
利用reduce可以轻松将一个string转换成int,例如
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
return reduce(fn, map(char2num, s))
filter()
过滤函数,给定一个序列和一个函数,函数依次作用于序列并根据结果的True/False决定是否丢弃。
def is_odd(n):
return n % 2 == 1
>>> filter(is_odd, range(0, 10))
[1, 3, 5, 7, 9]
例如删除1-100之间的素数。
def isn_prime(num):
if num == 1:
return True
for i in range(2, int(math.sqrt(num)) + 1):
if (num % i == 0):
return True
return False
filter(isn_prime, range(1, 101))
sorted()
对一个list排序,默认对数字是升序排序,字符串则是首字母ASCII码。sorted()是一个高阶函数,可以输入一个比较函数实现自定义排序。
>>> sorted([13, 2, 90, 33, 14, 5, 1])
[1, 2, 5, 13, 14, 33, 90]
def reversed_cmp(x, y):
if x > y:
return -1
elif x == y:
return 0
else:
return 1
>>> sorted([13, 2, 90, 33, 14, 5, 1], reversed_cmp)
[90, 33, 14, 13,5, 2, 1]
3.返回函数和闭包
高阶函数除了接收函数作为参数,还可以把函数作为结果值返回。返回的函数包含了相关的参数。
def delay_sum(*args):
def sum():
ans = 0
for n in args:
ans = ans + n
return ans
return sum
>>> f = delay_sum(1, 2, 3, 4)
>>> f()
10
闭包内部函数可以引用外部函数的参数和局部变量,外部函数返回内部函数时,相关的参数和变量都保存在返回的函数中。每次调用外部函数都会返回一个新的函数,即使传入相同的参数。因此不同的返回函数相互之间没有影响。
返回函数不要引用任何后续会发生变化的变量,尤其是循环变量。返回函数只有在显式调用时才会使用变量执行。
def counter():
fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
>>> f1, f2, f3 = counter()
>>> f1()
9
>>> f2()
9
>>> f3()
9
一定要引用循环变量时可以新建一个函数,绑定循环变量。
def counter():
fs = []
for i in range(1, 4):
def f(j):
def g():
return j * j
return g
fs.append(f(j))
return fs
>>> f1, f2, f3 = counter()
>>> f1()
1
>>> f2()
4
>>> f3()
9
或者用匿名函数lambda来实现。
>>> f1, f2, f3 = [(lambda i = i:i * i) for i in range(1, 4)]
4.匿名函数lambda
简单的形式可以直接使用匿名函数lambda *args:option
,匿名函数只能有一个表达式,但是没有名字,因此不用担心函数名冲突。
匿名函数可以赋值给一个变量,也可以作为返回值。
def test_lambda(x, y):
return lambda: x * x + y * y
匿名函数作为参数传入到高级函数中,具有简单直观的效果。
>>> map(lambda x:x * x, range(1, 10))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
5.装饰器Decorator
对于函数对象,在代码运行期间动态增加功能而没有修改原函数的方式称为装饰器。本质上装饰器就是一个返回函数的高阶函数。
def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
定义好了Decorator之后,可用@
将它置于函数的定义处,这样执行该函数时就会执行装饰器。即相当于执行了func = log(func)
@log
def test():
print 'Hello world!'
>>> test()
call test():
Hello world!
如果decorator本身需要传入参数,那就得写一个返回decorator的高阶函数。
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
6.偏函数
可以把一个函数的某些参数固定住,然后返回一个新的函数。
import functools
int2 = functool.partial(int, base = 2)
>>> int2('1001')
9
实际上就相当于
kw = {'base' : 2}
int('1001', kw)