python函数式编程

一个对象就是附有若干过程(procedure)的一段数据。。。一个闭包(closure)就是附有一段数据的一个过程(procedure)。
python集面向过程面向对象面向函数编程于一身,除了效率略低代码补全略弱以外堪称完美。python把函数式编程放到了至关重要的位置,在内置模块中(即built_in模块),包含map,filter等函数式编程关键组件。map,filter都是对象,是class类型的,跟range一样,一切皆class,他们都是可以遍历的对象。要想直接查看他们的内容,需要使用list转化一下

x=map(lambda x:x+1,[1,2,3])   #x是map类型的
list(x) #输出为2,3,4
list(filter(lambda x:x>3,map(lambda x:x+1,[1,2,3,4,5])))  #输出为4,5,6

zip(iterable1,iterable2,iterable3,....),zip函数将若干个可迭代对象组装成一个可迭代对象,目标对象的长度为min(len1,len2,len3...)
python3把reduce及其它一些常用函数放到了functools模块中,那么为什么要这样做呢?因为map和filter产生的结果仍旧是一个集合,把它们定义成class可以延迟计算,节省空间和时间;而reduce返回值为一个值,更像函数,所以把它放到了functools模块。

In[64]: from functools import *
In[65]: reduce(lambda x,y:x+y,range(10))
Out[65]: 45

reduce的定义def reduce(function, sequence, initial=None),注意最后一个默认参数initial=None。这个参数可以指定初始值。

itertools模块迭代器模块。

一、什么是函数式编程

函数式编程使用一系列的函数解决问题。函数仅接受输入并产生输出,不包含任何能影响产生输出的内部状态。也就是说,中间处理过程中不显式进行临时变量存储,一切都是用函数来完成。
在一个函数式的程序中,输入的数据“流过”一系列的函数,每一个函数根据它的输入产生输出。函数式风格避免编写有“边界效应”(side effects)的函数:修改内部状态,或者是其他无法反应在输出上的变化。完全没有边界效应的函数被称为“纯函数式的”(purely functional)。避免边界效应意味着不使用在程序运行时可变的数据结构,输出只依赖于输入。
可以认为函数式编程刚好站在了面向对象编程的对立面。对象通常包含内部状态(字段),和许多能修改这些状态的函数,程序则由不断修改状态构成;函数式编程则极力避免状态改动,并通过在函数间传递数据流进行工作。但这并不是说无法同时使用函数式编程和面向对象编程,事实上,复杂的系统一般会采用面向对象技术建模,但混合使用函数式风格还能让你额外享受函数式风格的优点。

二、函数式编程的优势

  1. 逻辑可证
    这是一个学术上的优点:没有边界效应使得更容易从逻辑上证明程序是正确的(而不是通过测试)。
  2. 模块化
    函数式编程推崇简单原则,一个函数只做一件事情,将大的功能拆分成尽可能小的模块。小的函数更易于阅读和检查错误。
  3. 组件化
    小的函数更容易加以组合形成新的功能。
  4. 易于调试
    细化的、定义清晰的函数使得调试更加简单。当程序不正常运行时,每一个函数都是检查数据是否正确的接口,能更快速地排除没有问题的代码,定位到出现问题的地方。
  5. 易于测试
    不依赖于系统状态的函数无须在测试前构造测试桩,使得编写单元测试更加容易。
  6. 更高的生产率
    函数式编程产生的代码比其他技术更少(往往是其他技术的一半左右),并且更容易阅读和维护。

三、函数式编程特征

  • 函数具有首要地位 (对象)。也就是说,能对“数据”做什么事,就要能对函数本身做到那些事(比如将函数作为参数传递给另外一个函数)。
  • 将递归作为主要的控制结构。在有些函数式语言中,都不存在其它的“循环”结构。
  • 列表处理作为一个重点(例如,Lisp语言的名字)。列表往往是通过对子列表进行递归取代了循环。
  • “纯”函数式语言会完全避免副作用。这么做就完全弃绝了命令式语言中几乎无处不在的这种做法:将第一个值赋给一个变量之后为了跟踪程序的运行状态,接着又将另外一个值赋给同一个变量。
  • 函数式编程不是不鼓励就是完全禁止使用语句,而是通过对表达式(换句话说,就是函数加上参数)求值(evaluation of expressions)完成任务. 在最纯粹的情形下,一个程序就是一个表达式(再加上辅助性的定义)
  • 函数式编程中最关心的是要对什么进行计算,而不是要怎么来进行计算。
  • 在很多函数式编程语言中都会用到“高阶”(higher order)函数 (换句话说,高阶函数就是对对函数进行运算的函数进行运算的函数)。

函数式编程的倡导者们认为,所有这些特性都有助于更快地编写出更多更简洁并且更不容易出Bug的代码。而且,计算机科学、逻辑学和数学这三个领域中的高级理论家发现,函数式编程语言和程序的形式化特性在证明起来比命令式编程语言和程序要简单很多。

四、去掉if

Python会对布尔表达式求值进行“短路”处理。这就为我们提供了一个if/elif/else分支语句的表达式版(假设每个分支只调用一个函数,不是这种情况时也很容易组织成重新安排成这种情况)。

# Normal statement-based flow control
if <cond1>:   func1()
elif <cond2>: func2()
else:         func3()
 
# Equivalent "short circuit" expression
(<cond1> and func1()) or (<cond2> and func2()) or (func3())
 
# Example "short circuit" expression
>>> x = 3
>>> def pr(s): return s
>>> (x==1 and pr('one')) or (x==2 and pr('two')) or (pr('other'))
'other'
>>> x = 2
>>> (x==1 and pr('one')) or (x==2 and pr('two')) or (pr('other'))
'two'

我们的表达式版本的条件调用看上去可能不算什么,更象是个小把戏;然而,如果我们注意到lambda算子必须返回一个表达式,这就更值得关注了。既然如我 们所示,表达式能够通过短路包含一个条件判断,那么,lambda表达式就是个完全通用的表达条件判断返回值的手段了。

>>> pr = lambda s:s
>>> namenum = lambda x: (x==1 and pr("one")) 
....                  or (x==2 and pr("two")) 
....                  or (pr("other"))
>>> namenum(1)
'one'
>>> namenum(2)
'two'
>>> namenum(3)
'other'

上面的函数必须有返回值,否则默认返回None,也就相当于False。所以在函数式编程中一切函数都要有确定的返回值,如果是void就默认成False了。

五、去掉循环

去掉for

for e in lst:  func(e)      # statement-based loop
map(func,lst)           # map()-based loop

去掉whilte

# statement-based while loop
while <cond>:
    <pre-suite>
    if <break_condition>:
        break
    else:
        <suite>
 
# FP-style recursive while loop
def while_block():
    <pre-suite>
    if <break_condition>:
        return 1
    else:
        <suite>
    return 0
 
while_FP = lambda: (<cond> and while_block()) or while_FP()
while_FP()

下面看一个具体的例子

# imperative version of "echo()"
def echo_IMP():
    while 1:
        x = raw_input("IMP -- ")
        if x == 'quit':
            break
        else
            print x
echo_IMP()
 
# utility function for "identity with side-effect"
def monadic_print(x):
    print x
    return x
 
# FP version of "echo()"
echo_FP = lambda: monadic_print(raw_input("FP -- "))=='quit' or echo_FP()
echo_FP()

六、常用函数实例

map

def format_name(s):
    return s[0].upper() + s[1:].lower()
    
print map(format_name, ['adam', 'LISA', 'barT'])

reduce

def f(x, y):
    return x + y
    print reduce(f, [1, 3, 5, 7, 9])  # 25

def prod(x, y):
    return x * y
print reduce(prod, [2, 4, 5, 7, 12]) # 3360

filter

def is_odd(x):
    return x % 2 == 1
print filter(is_odd, [1, 4, 6, 7, 9, 12, 17]) # [1, 7, 9, 17]

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

import math
def is_sqr(x):
    r = int(math.sqrt(x))
    return r*r==x
print filter(is_sqr, range(1, 101)) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

七、Python闭包

闭包就是外层函数的局部变量打包传递给内层函数,外层函数局部变量再怎么变化也不能影响已经发送出去的数据包。

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3= count()
print f1() # 9
print f2() # 9
print f3() # 9

def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            def g():
                return j*j
            return g
        r = f(i)
        fs.append(r)
    return fs
f1, f2, f3 = count()
print f1(), f2(), f3() # 1 4 9

其它有用的模块

一个神奇的模块:pipe。这个模块可以用类似管道的书写方式来写流式语句。
functional模块

原文地址:https://www.cnblogs.com/weiyinfu/p/6308616.html