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的博客大概也坚持了将近两周,我只是以自己最好理解的方式来整理一下目前我看到的资料。如果有什么错误,欢迎指正~
- 【python学习笔记】Python函数式编程
- python学习笔记(四) - 函数式编程
- Python学习笔记<函数式编程>
- Python学习笔记2:函数式编程
- 【Python学习笔记】函数式编程
- "Python"学习笔记----函数式编程
- Python学习笔记:函数式编程工具
- Python学习笔记11:Python函数和函数式编程
- python 学习笔记---函数式编程之高阶函数
- 【Python学习笔记】函数式编程:高阶函数
- 【Python学习笔记】函数式编程:高阶函数filter
- 【Python学习笔记】函数式编程:高阶函数sorted
- 【python学习笔记】函数式编程:返回函数
- 【Python学习笔记】函数式编程:匿名函数lambda
- 【Python学习笔记】函数式编程:偏函数
- Python学习笔记,函数式编程,高阶函数
- python基础学习笔记<函数式编程与模块>
- Python学习笔记——函数式编程
- 我的微信开发学习笔记(1):基础知识
- iOS界面编程-UIActionSheet
- list 函数 同时为多个变量赋值
- UINavigationBar美化
- 修改系统鼠标左右按键快速切换
- Python学习笔记<函数式编程>
- JavaScript高级程序设计第24章(最佳实践)
- [数论]矩阵快速幂
- 简单谈谈硬编码和软编码
- 1048 石子归并
- java初级 之主要类的总结
- Mining Massive Datasets课程笔记(三)
- Codeforces Round #324 (Div. 2) B. Kolya and Tanya
- db2move 导入导出数据库