您的位置:首页 > 编程语言 > Python开发

python学习(3)函数式编程

2016-03-01 19:23 621 查看

1.函数式编程(functional programming)

是一种编程方法,或者说是编程模式,它将电脑运算视为函数的计算、不需要变量因而不会产生副作用、支持高阶函数(可以接受函数作为参数)。

Python并不是纯的函数式编程,它允许有变量,支持闭包,有限的支持匿名函数。

与以前的C++不同的是python的变量是可以指向函数的,而函数名其实也是一个指向函数的变量

可以看看下面的例子:

f = abs

f(-10)

当然我们可以想到指向函数的变量其实也可以作为函数参数,这就相当于函数作为参数,就是我们说的高阶函数

看下面的例子:

def add(x, y, f):

return f(x) + f(y)

add(-5, 6, abs)



2.几个python内置的高阶函数

map():

接受一个函数f和一个list,list里的元素依次通过f的处理,然后生成一个新的list。

看这个例子:

def format_name(s):

return s[0].upper()+s[1:].lower()

print map(format_name, ['sam', 'LIly', 'TOM'])

输出:['Sam', 'Lily', 'Tom']

reduce():

接受一个函数f和一个list,f必须接受两个参数,取list中前两个元素用f处理,结果再作为参数和后面的元素一起用f处理,依次类推。

看下面的例子:

from functools import reduce

def add(x, y):

return x + y

reduce(add, [1, 3, 5, 7, 9])

输出:25

filter():

用于过滤序列,接受一个函数f和一个list,函数f对list中每个元素进行判断,返回True或False,过滤掉不符合条件的元素,生成由符合条件的元素组成的序列。

例如下面这个过滤偶数的例子:

def is_odd(x):

return x % 2 == 1

filter(is_odd, [1, 4, 6, 7, 9, 12, 17])



sorted():

用于对list进行排序,第二个参数可以省略也可以传入一个函数cmp,来定义排序的规则:顺序的返回-1,逆序返回1,相等返回0。第三个参数如果设为reverse=True可以在原来的基础上逆序排序。

看下面的例子:

def cmp_ignore_case(s1, s2):

if s1.upper()<s2.upper():

return -1

else:

return 1

print sorted(['bob', 'about', 'Zoo', 'Credit'], key=cmp_ignore_case, reverse=True)

结果:['Zoo', 'Credit', 'bob', 'about']



3.返回函数与闭包

返回函数:

Python可以返回函数,但有一点需要注意的:

看这个例子:

def calc_prod(lst):

def prod(x1, x2):

return x1 * x2

def c_prod():

return reduce(prod, lst)

return c_prod

f = calc_prod([1, 2, 3, 4])

print f()

输出:24

这里返回函数的时候并不会执行,再调用f()的时候才会执行。

闭包:

先简单的下个定义:内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure

但是为什么要这样子做呢?我们结合下面这个例子来理解一下:

def line_conf(a, b):

def line(x):

return ax + b

return line

line1 = line_conf(1, 1)

line2 = line_conf(4, 5)

print(line1(5), line2(5))

显然如果我们只是定义一个接受a、b、x三个参数的函数也是可以的,但这样我们每次就需要传入三个参数,显然麻烦很多,特别是当a、b两个参数较少改变的时候,上面代码使用闭包的简便性就体现出来了。这就是说闭包能提高程序的复用性。

一个需要注意的点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。这个可以看看廖雪峰老师慕课网上的python进阶教程深入了解。



4.匿名函数

Python匿名函数的使用比Java的简单得多:用关键字lambda且只能有一个表达式。

看下面的例子:

print filter(lambda s:s and len(s.strip()) > 0, ['test', None, '', 'str', ' ', 'END'])

这个例子的功能是过滤空字符串,冒号前面的x是参数,后面是表达式。



5.装饰器

装饰器(Decorator用于增强函数的功能。本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。

我们可以用@语句简化像f = decorate(f)这样的代码。

看下面的例子:

def log(f):

def fn(x):

print 'call ' + f.__name__ + '()...'

return f(x)

return fn

@log

def factorial(n):

return reduce(lambda x,y: x*y, range(1, n+1))

print factorial(10)

输出:

call factorial()...

3628800

但是,我们发现log()函数只适用于一个参数的函数。为了让它适用各种参数数量,我们需要做一些修改:

def log(f):

def fn(*args, **kw):

print 'call ' + f.__name__ + '()...'

return f(*args, **kw)

return fn

然后有时,我们需要log()函数打印不同的语句,这就需要我们对装饰器传入参数。

思路是这个样子的:带参数的log函数首先返回一个decorator函数,再让这个decorator函数接收my_func并返回新函数。

看下面的例子:

def log(prefix):

def log_decorator(f):

def wrapper(*args, **kw):

print '[%s] %s()...' % (prefix, f.__name__)

return f(*args, **kw)

return wrapper

return log_decorator



@log('DEBUG')

def test():

pass

print test()

输出:

[DEBUG] test()...

None

装饰器有时会改变函数的一些属性,比如函数名等,为了保存原有的函数信息,我们可以在参数为原函数的函数下加一句 @functools.wraps(f)



6.偏函数

我们可以用 functools.partial() 减少原函数参数的数量,创建一个新函数。

看下面的例子:

int2 = functools.partial(int, base=2)

Int函数默认第二个参数为10,表示进制,我们也可以改变第二个参数,例子的int2表示一个二进制的类型转换函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: