Python 函数式编程

慕课网 http://www.imooc.com/

1、变量可以指向一个函数(函数名相当于一个变量)

1
2
3
4
5
import math
def add(x, y, fun):
    return fun(x) + fun(y)
 
print(add(25, 9, math.sqrt))

2、map函数

【python 2】

Help on built-in function map in module __builtin__:

map(...)

    map(function, sequence[, sequence, ...]) -> list

    Return a list of the results of applying the function to the items of

    the argument sequence(s).  If more than one sequence is given, the

    function is called with an argument list consisting of the corresponding

    item of each sequence, substituting None for missing values when not all

    sequences have the same length.  If the function is None, return a list of

    the items of the sequence (or a list of tuples if more than one sequence).


【python 3】

class map(object)

 |  map(func, *iterables) --> map object

 |

 |  Make an iterator that computes the function using arguments from

 |  each of the iterables.  Stops when the shortest iterable is exhausted.

 |

 |  Methods defined here:

 |

 |  __getattribute__(self, name, /)

 |      Return getattr(self, name).

 |

 |  __iter__(self, /)

 |      Implement iter(self).

 |

 |  __new__(*args, **kwargs) from builtins.type

 |      Create and return a new object.  See help(type) for accurate signature.

 |

 |  __next__(self, /)

 |      Implement next(self).

 |

 |  __reduce__(...)

 |      Return state information for pickling.

1
2
3
4
5
6
import math
 
def square(x):
    return math.pow(float(x), 2.0)
# python3中,map的返回值已经不是list,而是iterators
print(list(map(square, range(10))))

由于list包含的元素可以是任何类型,因此,map() 不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。

3、reduce函数

reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

例如,编写一个f函数,接收x和y,返回x和y的和:

def f(x, y):
    return x + y

调用 reduce(f, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:

先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。

上述计算实际上是对 list 的所有元素求和。虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。

reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:

reduce(f, [1, 3, 5, 7, 9], 100)

结果将变为125,因为第一轮计算是:

计算初始值和第一个元素:f(100, 1),结果为101

1
2
3
4
def prod(x, y):
    return x * y
# 相当于 3*2*4*5
print reduce(prod, [2, 4, 5], 3)

4、filter函数

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。(python2返回list,python3返回iterators

1
2
3
4
5
6
# python 2
import math
def is_sqr(x):
    return x == int(math.sqrt(x)) ** 2
 
print filter(is_sqr, range(1, 101))

5、自定义函数对象

1
2
3
4
def cmp_ignore_case(s1, s2):
    return cmp(s1.lower(), s2.lower())
 
print sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case)

6、返回函数

Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!

例如,定义一个函数 f(),我们让它返回一个函数 g,可以这样写:

def f():
    print 'call f()...'
    # 定义函数g:
    def g():
        print 'call g()...'
    # 返回函数g:
    return g

仔细观察上面的函数定义,我们在函数 f 内部又定义了一个函数 g。由于函数 g 也是一个对象,函数名 g 就是指向函数 g 的变量,所以,最外层函数 f 可以返回变量 g,也就是函数 g 本身。

调用函数 f,我们会得到 f 返回的一个函数:

>>> x = f()   # 调用f()
call f()...
>>> x   # 变量x是f()返回的函数:
<function g at 0x1037bf320>
>>> x()   # x指向函数,因此可以调用
call g()...   # 调用x()就是执行g()函数定义的代码

请注意区分返回函数和返回值:

def myabs():
    return abs   # 返回函数
def myabs2(x):
    return abs(x)   # 返回函数调用的结果,返回值是一个数值

返回函数可以把一些计算延迟执行。例如,如果定义一个普通的求和函数:

def calc_sum(lst):
    return sum(lst)

调用calc_sum()函数时,将立刻计算并得到结果:

>>> calc_sum([1, 2, 3, 4])
10

但是,如果返回一个函数,就可以“延迟计算”:

def calc_sum(lst):
    def lazy_sum():
        return sum(lst)
    return lazy_sum

# 调用calc_sum()并没有计算出结果,而是返回函数:

>>> f = calc_sum([1, 2, 3, 4])
>>> f
<function lazy_sum at 0x1037bfaa0>

# 对返回的函数进行调用时,才计算出结果:

>>> f()
10

由于可以返回函数,我们在后续代码里就可以决定到底要不要调用该函数。

1
2
3
4
5
6
7
8
9
# 编写一个函数calc_prod(lst),它接收一个list,返回一个函数,返回函数可以计算参数的乘积
def calc_prod(lst):
    def lazy_prod():
        def f(x, y):
            return x * y
        return reduce(f, lst, 1) # 初始值为1
    return lazy_prod
f = calc_prod([1, 2, 3, 4])
print f()

7、闭包

在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问。

def calc_sum(lst):
    def lazy_sum():
        return sum(lst)
    return lazy_sum

像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)

闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。

# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。

原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:

>>> f1()
9     # 因为f1现在才计算i*i,但现在i的值已经变为3

因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 返回闭包不能引用循环变量,请改写count()函数,让它正确返回能计算1x1、2x2、3x3的函数
def count():
    fs = []
    for i in range(1, 4):
        def fun(x):
            def square():
                return x ** 2
            return square
 
        fs.append(fun(i))
    return fs
 
f1, f2, f3 = count()
print f1(), f2(), f3()

8、匿名函数

高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。

在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算 f(x)=x时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:

>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

通过对比可以看出,匿名函数 lambda x: x * x 实际上就是:

def f(x):
    return x * x

关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。

匿名函数有个限制,就是只能有一个表达式不写return,返回值就是该表达式的结果。

使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码:

>>> sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))
[9, 5, 3, 1, 0]

返回函数的时候,也可以返回匿名函数:

>>> myabs = lambda x: -x if x < 0 else x 
>>> myabs(-1)
1
>>> myabs(1)
1
1
2
3
4
5
6
7
8
# 利用匿名函数简化以下代码
def is_not_empty(s):
    return s and len(s.strip()) > 0
 
print filter(is_not_empty, ['test', None, '', 'str', '  ', 'END'])
 
# 简化后版本
print filter(lambda s: s and len(s.strip()) > 0, ['test', None, '', 'str', '  ', 'END'])




posted @ 2015-12-15 15:35  指上弹兵赵小括  阅读(196)  评论(0编辑  收藏  举报