Python 函数式编程

1.什么是函数式编程

Wiki上对Functional Programming的定义:html

In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions[1] or declarations[2] instead of statements. In functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function f twice with the same value for an argument x will produce the same result f(x) each time.** Eliminating side effects, i.e. changes in state that do not depend on the function inputs, can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming. **python

"函数式编程"是一种"编程范式"(programming paradigm),一种构建计算机程序结构和元素的风格/模式。它把运算看成是数据函数的计算,避免了多变的状态和易变的数据。它是一种声明性编程范式,意味着程序是由表达式或声明完成的而不是语句。在函数代码中,函数的输出值只依赖于对这个函数的输入,所以以一样的参数值x调用函数f两次,每次获得的结果是相同的f(x)。消除反作用,即状态的改变再也不依赖于函数的输入,这使理解和预测程序的行为更加容易,这也是发展函数式编程的主要动力。****express

所谓"反作用"(side effect),指的是函数内部与外部互动(最典型的状况,就是修改全局变量的值),产生运算之外的其余结果。
函数式编程强调没有"反作用",意味着函数要保持独立,全部功能就是返回一个新的值,没有其余行为,尤为是不得修改外部变量的值。编程

和声明性编程对应的是命令式编程(imperative programming), 它在源程序中使用命令改变状态,最简单的例子就是赋值。存在的反作用是可能改变程序状态的值。所以函数没有返回值是有意义的。因为它们缺乏引用透明性(referential transparency),即根据程序的执行状态在不一样的时间,相同的表达式可能会产生不一样的结果。闭包

引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任什么时候候只要参数相同,引用函数所获得的返回值老是相同的。app

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量(应该也存在不是纯粹的函数式编程,使用函数式编程解决局部问题,同时也存在变量),所以,任意一个函数,只要输入是肯定的,输出就是肯定的,这种纯函数咱们称之为没有反作用。而容许使用变量的程序设计语言,因为函数内部的变量状态不肯定,一样的输入,可能获得不一样的输出,所以,这种函数是有反作用的。编程语言

函数式编程就是如何编写程序的方法论。
它属于"结构化编程"的一种,主要思想是把运算过程尽可能写成一系列嵌套的函数调用。举例来讲,如今有这样一个数学表达式:ide

(1 + 2) * 3 - 4

传统的过程式编程,可能这样写:函数式编程

var a = 1 + 2;
var b = a * 3;
var c = b - 4;

函数式编程要求使用函数,咱们能够把运算过程定义为不一样的函数,而后写成下面这样:函数

var result = subtract(multiply(add(1,2), 3), 4);

这就是函数式编程。

2.函数即变量(first class function)

Python中一切皆为对象。函数也不例外,且函数与其余数据类型同样,处于平等地位。
函数能够赋值给变量,也能够做为参数,传入另外一个函数,或者做为别的函数的返回值。函数名其实就是指向函数的变量,它能够被赋其余值。

这样才能快捷实施函数式编程,C语言里函数与变量不平等的,或许借助函数指针却是能够实现,但颇为麻烦。

函数赋值给其余变量

>>> abs(-10)
10
>>> foo = abs
>>> foo(-10)
10

函数名被赋其余变量

>>> abs
<built-in function abs>
>>> abs = 10
>>> abs
10

函数做为参数传递给另外一函数

>>> def add(x, y, foo):
...     return foo(x) + foo(y)
... 
>>> add(-10, 3, abs)
13

函数做为返回值返回

>>> def foo():
    return abs
... ... 
>>> fun = foo()
>>> fun(-10)
10
3.匿名函数lambda

lambda表达式用于建立匿名函数,是一种简化函数定义的快速方法。不像def那样能够执行多重语句和注释,lambda形式定义的函数没有def形式的强大。优势是快速简单,一条语句就可定义一个函数。
lambda语法以下:

lambda arguments: expression

lambda定义一个求和函数add。

add = lambda x, y: x + y

效果和def形式定义的是同样的。

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

lambda表达式一般是直接嵌入在须要函数的地方,且该函数能使用一个表达式完整描述,不大会直接将lambda表达式命令成函数。这虽然很酷,可是不方便拓展,若是一开始就须要给函数命名,应该使用def形式定义。

4.编程风格

打印斐波那契数列前10个。

  • 命令式风格,使用了循环,有变量赋值语句。(如何解释反作用的缘由?)
def fibonacci(n, first=0, second=1):
    while n != 0:
        print(first, end="\n") # side-effect
        n, first, second = n - 1, second, first + second # assignment
fibonacci(10)
  • 函数式风格,使用了递归方式
fibonacci = (lambda n, first=0, second=1:
    "" if n == 0 else
    str(first) + "\n" + fibonacci(n - 1, second, first + second))
print(fibonacci(10), end="")

此处的lambda表达式略微复杂,换成def的形式:

def fibonacci(n, first=0, second=1):
    if n == 0:
        return ''
    else:
        return str(first) + "\n" + fibonacci(n - 1, second, first + second)
print(fibonacci(10), end="")

循环是在描述咱们该如何地去解决问题。
递归是在描述这个问题的定义。

简单点理解,函数式编程就是把函数当普通的变量或对象同样使用,函数用作参数或返回值。函数自身带有逻辑计算,当变量使用能够获得很是高效的代码。

4.高阶函数

传统的说,Python是一种非函数式语言(non-functional),但在编码时可使用函数式风格。Python中的lambda,高阶函数(map, reduce, filter),偏函数(partial function),闭包(closure),装饰器(decorator)都有函数式思想。经过 Python 中的高阶函数稍稍体会下函数式编程的趣味。
把函数做为参数传入的函数,这样的函数称为高阶函数。Python中知名高阶函数有map, reduce, filter。

  • map

    | 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.

map()传入的第一个参数是函数,第二个参数是Iterable对象,便可迭代的对象,如list,dict,str都是Iterable对象。map将函数func依次做用到Iterable对象的元素上,返回一map对象。(map对象是?)
以下将list中元素平方后获得新的list。

>>> ret= map(lambda x: x*x, list(range(5)))
>>> print(ret)
<map object at 0x029AE4B0>
>>> print(list(ret))
[0, 1, 4, 9, 16]

不是很严格的map()实现:

from collections import Iterable

def map(func, a_iterable):
    result = []
    if isinstance(a_iterable, Iterable) is False:
        raise TypeError('%s object is not iterable' % type(a_iterable))
    else:
        for item in a_iterable:
            result.append(func(item)) 
    return result
  • reduce
    Python3里 reduce() 在 functools 模块下。

    functools.reduce = reduce(...)
    reduce(function, sequence[, initial]) -> value
    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5). If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.

reduce()最少接收2个参数,最多接收3个参数,第2个参数要求可迭代的。reduce()做用效果:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

>>> from functools import reduce
>>> reduce(lambda x, y: x+y, [1, 2, 3], 10)
16
>>> reduce(lambda x, y: x+y, [1, 2, 3])
6

map() 和 reduce() 结合使用实现 str 到 int 的过程,简洁又酷炫。

from functools import reduce

def str2int(a_str):
    
    char2int = lambda x :{'0':0, '1':1, '2':2, '3':3, '4': 4, '5': 5,
         '6': 6, '7':7, '8': 8, '9': 9}[x]

    return reduce(lambda x, y: x*10+y, map(char2int, a_str))

print(str2int('1234'))
  • filter

    class filter(object)
    | filter(function or None, iterable) --> filter object
    |
    | Return an iterator yielding those items of iterable for which function(item)
    | is true. If function is None, return the items that are true.

filter()也接收一个函数和一个序列。和 map()不一样的时,filter()把传入的函数依次做用于每一个元素, 而后根据返回值是 True 仍是 False 决定保留仍是丢弃该元素。
如获得序列中的整数:

>>> ret = filter(lambda x: x if x>0 else None, [1, -2, 3, -4, 0])
>>> print(ret)
<filter object at 0x029AEEF0>
>>> print(list(ret))
[1, 3]
  • sorted

    sorted(iterable, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.
    |
    A custom key function can be supplied to customise the sort order, and the
    reverse flag can be set to request the result in descending order.

sorted()函数也是一个高阶函数,它还能够接收一个 key 函数来实现自定义的排序。
按绝对值排序

>>> sorted([1, -2, -3, 4], key=abs)
[1, -2, -3, 4]

问题:
有这样一个 list :['1y','3m','1m','7d','5d','1d','12h','6h','3h']
其中 y 表示年, m 表示月, d 表示天, h 表示小时,前面的数字表示对应的时间
问如何用 sort 在一行内按照年>月>天>小时或者反过来的顺序进行排序?

>>> a_list = ['1y','3m','1m','7d','5d','1d','12h','6h','3h']
>>> sorted(a_list, key = lambda x: {'y':365*24, 'm':30*24, 'd':24, 'h':1}[x[-1]] * int(x[:-1]))
['3h', '6h', '12h', '1d', '5d', '7d', '1m', '3m', '1y']

参考:

1.wiki-Functional programming
2.Python函数式编程指南(一):概述
3.函数式编程扫盲篇
4.函数式编程初探
5.函数式编程

完---若有错漏,请指教:)

相关文章
相关标签/搜索