Python学习笔记<函数式编程>

来源:互联网 发布:淘宝卖家后台无法登陆 编辑:程序博客网 时间:2024/05/16 17:51

把酒祝东风,且共从容
垂杨紫陌洛城东
总是当时携手处,游遍芳丛

聚散苦匆匆,此恨无穷
今年花胜去年红
可惜明年花更好,知与谁同?

浪淘沙双调小令 欧阳修

有人说在python中一切都是对象,让我们今天来共同探寻一下Python中的函数究竟是怎么对象化的

本文的参考文献有:

  • python进阶教程之函数对象
  • Dive Into Python3
  • 廖雪峰的官方网站

本文目录

  • Python中的神奇对象函数
    • 函数也可以做对象
    • 自动构建一组函数
    • 从文件中读取函数配置
    • 用生成器来生成函数
    • 整理一下思路
  • 内置的高阶函数
    • map
    • reduce
    • filter
    • sorted
  • 还有什么
    • 匿名函数
    • 深呼吸一下装饰器
    • 最后的话

Python中的神奇对象——函数

在英文中,根据词尾,名词的复数形式也会不同。
让我们先看一下三段代码。
第一段是比较常规的思维,传入这个名词,然后进行判断,得到复数形式。

def plural(noun):              if re.search('[sxz]$', noun):                    return re.sub('$', 'es', noun)             elif re.search('[^aeioudgkprt]h$', noun):          return re.sub('$', 'es', noun)    elif re.search('[^aeiou]y$', noun):                return re.sub('y$', 'ies', noun)         else:        return noun + 's'

上面这段代码用到了re模块,如果你对这个模块还不太熟悉,可以看这里。
当然先不理解也可以,我们的重点是了解python中函数的特性不是么?
很平淡无奇,不是么?

看看下面这段抽象了一点的:

函数也可以做对象~

import redef match_sxz(noun):    return re.search('[sxz]$', noun)def apply_sxz(noun):    return re.sub('$', 'es', noun)def match_h(noun):    return re.search('[^aeioudgkprt]h$', noun)def apply_h(noun):    return re.sub('$', 'es', noun)def match_y(noun):    return re.search('[^aeiou]y$', noun)def apply_y(noun):    return re.sub('y$', 'ies', noun)def match_default(noun):    return Truedef apply_default(noun):    return noun + 's'rules = ((match_sxz, apply_sxz),         (match_h, apply_h),         (match_y, apply_y),         (match_default, apply_default)         )def plural(noun):    for matches_rule, apply_rule in rules:        if matches_rule(noun):            return apply_rule(noun)#测试a=['apple','watch','agency']for i in a:    print('{0} : {1}'.format(i,plural(i)))

这里引入了python的一个概念——函数也是的对象!
可以将一对对的函数存在一个tuple中(rules)。

但是我们在这里是不是还可以继续简化?比如说:自动构建rule这个函数tuple?。
答案是可以,rule中每一对函数都是同样的返回类型。那么:

自动构建一组函数

import redef build_match_and_apply_functions(pattern, search, replace):    def matches_rule(word):                                             return re.search(pattern, word)    def apply_rule(word):                                               return re.sub(search, replace, word)    return (matches_rule, apply_rule)                           

在函数中定义两个函数,然后返回。

这样,我们只需要定义一个这样的数据结构:

patterns = \                                                          (    ('[sxz]$',           '$',  'es'),    ('[^aeioudgkprt]h$', '$',  'es'),    ('(qu|[^aeiou])y$',  'y$', 'ies'),    ('$',                '$',  's')                                   )rules = [build_match_and_apply_functions(pattern, search, replace)           for (pattern, search, replace) in patterns]

从文件中读取函数“配置”

你问我,可不可以再简单一点?
可以,比如这样:
从文件中读取这个patterns:

[sxz]$               $    es[^aeioudgkprt]h$     $    es[^aeiou]y$          y$    ies$                    $    s
import redef build_match_and_apply_functions(pattern, search, replace):      def matches_rule(word):        return re.search(pattern, word)    def apply_rule(word):        return re.sub(search, replace, word)    return (matches_rule, apply_rule)rules = []with open('plural4-rules.txt', encoding='utf-8') as pattern_file:      for line in pattern_file:                                              pattern, search, replace = line.split(None, 3)                     rules.append(build_match_and_apply_functions(                              pattern, search, replace))

你问:这个还可以写得再精炼一点么?
这个。。。还真可以。我们把从文件到rule的这一部分可以函数化:

用生成器来生成函数

def rules(rules_filename):    with open(rules_filename, encoding='utf-8') as pattern_file:        for line in pattern_file:            pattern, search, replace = line.split(None, 3)            #看这里!            yield build_match_and_apply_functions(pattern, search, replace)def plural(noun, rules_filename='plural5-rules.txt'):    for matches_rule, apply_rule in rules(rules_filename):        if matches_rule(noun):            return apply_rule(noun)    raise ValueError('no matching rule for {0}'.format(noun))

yield的意思是暂停当前函数,并返回调用者。
这里我们需要引入一个新的概念:Generator。
这个概念比较重要,但是我们现在在这里先不探讨了。

整理一下思路

我们发现,其实我们说了这么多,就是想证明一点:函数原来也可以像一个整数、字符串这样使用。这是一个重要的目标,我们必须意识到这一点:从今往后,一个函数不再是我们在c中理解的那种,而是一个向整数,字符串那样的对象!!

让我们稍微休息一下,我们马上就要看一下,在python中,函数作对象的意义:

内置的高阶函数

python中内置了几种比较常用的以函数为参数的函数(是不是有点绕口~),分别是map、reduce、filter和sort。在看看他们的定义之后,你其实已经可以将他们写出来了。

map

def func(x):    return  x+3result=map(func,[1,2,3,5,7])

返回结果result是:

[4,5,6,8,10]

你其实已经猜出来了,这无非是在[1,2,3,5,7]上进行了一次遍历,将每一个的值都传入第一个参数:func上。

我们来尝试完成一个自己的map试试:

#朴素的my_map :)def my_map(fun,lst):    res=[]    for i in lst:        res.append(fun(i))    return res

尝试一下:

result=my_map(func,[1,2,3,4,5])>>> result[4, 5, 6, 7, 8]

成功了!

reduce

至于reduce,嗯。它的效果是这样的:

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

首先计算temp=f(x1,x2),然后计算temp=f(temp,3),再然后temp=f(temp,x4)。。。
这个写出来也很简单:

def  my_reduce(fun,lst):    temp=lst[0]    for i in range(1,len(lst)):        temp=fun(temp,i)    return temp

我们攻克两个了!还有filter和sort!
如果你觉得累了没关系,作者写这篇博文可是用了将近一天的时间呢~

filter

我想你甚至可以从名字上猜测数来它是做什么的了:
没错,过滤

def is_odd(n):    return n % 2 == 1list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))

我们照例来实现一下,但是我这里用点小技巧简化一下:

def my_filter(fun,lst):    return [i for i in lst if fun(i)]

(其实上面的map也可以这样写哦)

sorted

我们根据名字就可以猜得一二
的确:

sorted([36, 5, -12, 9, -21])[-21, -12, 5, 9, 36]

这是一个排序高阶函数:
我们可以自定义排序的key

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

请注意key=str.lower,所以并不是以默认的ABCD…abc这样的顺序。而是以其小写决定的。

key就是一个函数。我们也可以自定义其返回值。

还有什么?

如果你还没有累,建议一直读下去,就算忘记了前面的大部分内容也没关系。只要保有这样一个印象就好:函数是对象。
接下来,我们要看这样几个问题:

  • 函数作为返回值
  • 匿名函数
  • 装饰器函数
  • 偏函数
    其实第一点我们之前的已经用到了,我们不再深入。先看看后三点:

匿名函数

先看看这样一段代码:

list(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 fun(x):    return x*x

但是明显简洁了很多,你没有必要再去为这个函数起一个名字了。
这叫做lambda表达式,在c++ 11中也已经支持了它。
lambda作为返回值也没有问题:

def build(x, y):    return lambda: x * x + y * y

深呼吸一下——装饰器

装饰器比前面几个略微复杂一些:
我们现在知道函数是对象,那么我们可以用函数给对象赋值,就像一个整形或者字符串一样:

def power(x):    return x*x#请使用函数名来赋值f=power#调用f(5)#输出25

现在看看这个函数:

def get_new_fun(fun):    def new_fun(x):        return 1+fun(x)    return new_fun

发生了什么?我们传入一个函数fun,构建了一个新函数。这就是所谓了装饰器模式:在不改变原函数的基础上构建新的函数。

我们可以通过

f=get_new_fun(power)

得到新的函数了!

还有一种方法,可以将函数直接定义为新函数

@get_new_fundef fun(x):    return x*xfun(5)#结果是26

最后的话

其实作者本人接触函数编程也只有一天,我写python的博客大概也坚持了将近两周,我只是以自己最好理解的方式来整理一下目前我看到的资料。如果有什么错误,欢迎指正~

2 0