Python5 函数式编程(Functional Programming)

高阶函数Higher-order function

变量可以指向函数

以abs()函数举例,把函数本身赋值给变量:

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

结论:函数本身也可以赋值给变量,即:变量可以指向函数。如果一个变量指向了一个函数,那么,可通过该变量来调用这个函数。直接调用abs()函数和调用变量f()完全相同。

函数名也是变量

对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!

注:由于abs函数实际上是定义在import builtins模块中的,所以要让修改abs变量的指向在其它模块也生效,要用import builtins; builtins.abs = ?

传入函数

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。编写高阶函数,就是让函数的参数能够接收别的函数。


map/reduce

Python内建了map()reduce()函数。

map()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

reduce()函数的用法是把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

举例

利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:[‘adam‘, ‘LISA‘, ‘barT‘],输出:[‘Adam‘, ‘Lisa‘, ‘Bart‘]

from functools import reduce

IN = [‘adam‘,‘LISA‘,‘barT‘]

def standarize(IN):
    return IN[0].upper() + IN[1:].lower()
print(list(map(standarize,IN)))

Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:

def prod(x,y):
    return x*y

print(reduce(prod,IN))

利用mapreduce编写一个str2float函数,把字符串‘123.456‘转换成浮点数123.456

from functools import reduce

IN = ‘123.456‘
decimal = 0
def str2float(x,y):
    global decimal
    if y == ‘.‘:
        return x+0.0

    if isinstance(x,int):
        return x*10+y  else:
      decimal = decimal + 1
      return x+y/10**decimaldef char2num(L):
    return {‘0‘: 0, ‘1‘: 1, ‘2‘: 2, ‘3‘: 3, ‘4‘: 4, ‘5‘: 5, ‘6‘: 6, ‘7‘: 7, ‘8‘: 8, ‘9‘: 9,‘.‘:‘.‘}[L]

print(reduce(str2float,map(char2num,IN)))

filter

Python内建的filter()函数用于过滤序列。

map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

把一个序列中的空字符串删掉,可以这么写:

def not_empty(s):
    return s and s.strip()

list(filter(not_empty, [‘A‘, ‘‘, ‘B‘, None, ‘C‘, ‘  ‘]))
# 结果: [‘A‘, ‘B‘, ‘C‘]

可见用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。

注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

用filter求素数

def main():
    for n in primes():
        if n < 100:
            print(n)
        else:
            break

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

def _not_divisible(n):
    return lambda x: x % n > 0  #余数

def primes():
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)

sorted

排序算法

排序的核心是比较两个元素的大小。Python内置的sorted()函数就可以对list进行排序。此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

我们再看一个字符串排序的例子,实现忽略大小写的排序:

>>> sorted([‘bob‘, ‘about‘, ‘Zoo‘, ‘Credit‘], key=str.lower)
[‘about‘, ‘bob‘, ‘Credit‘, ‘Zoo‘]

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True。

一组tuple排序

L=[(‘Bob‘,75),(‘Adam‘,92),(‘Bart‘,66),(‘Lisa‘,88)]
def by_name(t):
    return t[0]
L2=sorted(L,key=by_name)
print(L2)


返回函数

函数作为返回值

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

我们来实现一个可变参数的求和:

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:

>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>

调用函数f时,才真正计算求和的结果:

>>> f()
25

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

f1()f2()的调用结果互不影响。

闭包

注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。

另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:

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

f1, f2, f3 = count()

在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

你可能认为调用f1()f2()f3()结果应该是149,但实际结果是:

>>> f1()
9
>>> f2()
9
>>> f3()
9

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

再看看结果:

>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

缺点是代码较长,可利用lambda函数缩短代码。

小结

一个函数可以返回一个计算结果,也可以返回一个函数。

返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

时间: 2024-11-03 10:08:43

Python5 函数式编程(Functional Programming)的相关文章

面向函数范式编程(Functional programming)

函数编程(简称FP)不只代指Haskell Scala等之类的语言,还表示一种编程思维,软件思考方式,也称面向函数编程. 编程的本质是组合,组合的本质是范畴Category,而范畴是函数的组合. 首先,什么是函数式编程,这并没有唯一定义,它只是广泛聚合了一些编程风格的特性,我们可以将它与面向对象编程OOP进行对比, 两者区别是,OOP主要聚焦于数据的区别,而FP则注重数据结构的一致性. 面向对象: 数据和对数据的操作紧紧耦合 .对象隐藏它们操作的实现细节,其他对象调用这些操作只需要通过接口. .

编程范式:命令式编程(Imperative)、声明式编程(Declarative)和函数式编程(Functional)

主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 命令式编程:命令式编程的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么.比如:如果你想在一个数字集合 collection(变量名) 中筛选大于 5 的数字,你需要这样告诉计算机:第一步,创建一个存储结果的集合变量 results:第二步,遍历这个数字集合 collection:第三步:一个一个地判断每个数字是不是大于 5,如果是就将这个数字添加到结果集合变量 results 中.代码实现如下: List<int>

深入浅出 Python 函数式编程

1.函数式编程的定义与由来 如果程序中的函数仅接受输入并产生输出,即输出只依赖于输入,数据不可变,避免保存程序状态,那么就称为函数式编程(Functional Programming,简称FP,又称泛函编程). 这种风格也称声明式编程(Declarative Programming),与之相对的是指令式编程(Imperative Programming),后者中的对象会不断修改自身状态.函数式编程强调程序的执行结果比执行过程更重要,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算

我以为的函数式编程

函数式编程 函数式编程(functional programming)的思想相对于命令式编程(imperative programming),告诉计算机你要什么而不是告诉它要怎么做,举个例子: (defun fun(x) (list 'a (expt (car x) 2))) 这是函数是编程,而 (defun imp (x) (let* ((y (car x)) (z (expt y 2))) (list 'a z))) 是命令式编程,结果一样,但思想不同. 函数式编程还要尽量避免对函数的参数进

Java8函数式编程 (一) 数据流和lambda表达式

JDK 1.8中引入了函数式编程(functional programming,FP),如果您已习惯OOP,一定会感到困惑:什么是函数式编程?这样的编程模式有什么好处? 本文将通过简单的实例令读者对函数式编程有一个大体的了解. 我们知道OOP是以类为基础的,程序中必须首先抽象和定义class.那么FP创建的基础是什么?或者说在Java 8中,至少需要了解什么知识点才能实现基本的函数式编程呢? 本文将首先介绍在Java 8中使用FP所需的基本知识点: Lambda表达式 数据流 基本实例 Map<

简单聊聊:函数式编程

函数式编程 ( Functional Programming ) 是一种以函数为基础的编程方式和代码组织方式,能够带来更好的代码调试及项目维护的优势.本篇主要结合笔者在实际项目开发中的一些应用,简要谈谈函数式编程. 函数 在函数式编程中,任何代码可以都是函数,且要求具有返回值,如下示例 // 非函数式 var title = "Functional Programming"; var saying = "This is not"; console.log(sayin

Python笔记3#Python函数式编程

▲函数式编程Function Programming 函数时Python内建支持的一种封装.我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. 函数式编程也可以归结到面向过程的程序设计,但它的思想更接近数学计算. 函数式编程就是一种抽象度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量. 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回另一个函数. Py

Python进阶-函数式编程

花了一个多小时学习python的函数式编程,终于算入门了,这接近一万字的教程,原作者分了十几课,我融合在一起方便查阅. 函数式编程 functional,是编程的一种范式 特点有: 把计算视为函数而不是指令 纯函数式编程不需要变量,没有副作用,测试简单 支持高阶函数,代码简洁 Python支持函数式编程: python不是纯函数式语言,允许有变量 支持高阶函数,函数也可作为变量传入 支持闭包,有了闭包就能返回函数 有限度地支持匿名函数 高阶函数是什么 先了解以下概念: 1.变量可以指向一个函数,

Sth about 函数式编程(Functional Programming)

今天开会提到了函数式编程,针对不同类型的百年城方式,查阅了一部分资料,展示如下: 编程语言一直到近代,从汇编到C到Java,都是站在计算机的角度,考虑CPU的运行模式和运行效率,以求通过设计一个高效的编程语言,作为人与计算机之间沟通的桥梁.因为计算机本质上是串行执行一个个指令流,因此编程语言也被设计为命令式编程(Imperative Programming),先算什么再算什么,怎么输入怎么计算怎么输出,全部由编程人员决定. 后来,大家发现冯·诺伊曼结构将数据和指令平等化的思想能够帮助我们更好地对