把酒祝东风,且共从容
垂杨紫陌洛城东
总是当时携手处,游遍芳丛聚散苦匆匆,此恨无穷
今年花胜去年红
可惜明年花更好,知与谁同?
浪淘沙双调小令 欧阳修
有人说在python中一切都是对象,让我们今天来共同探寻一下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 re
def 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 True
def 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 re
def 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 re
def 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。在看看他们的定义之后,你其实已经可以将他们写出来了。
def func(x):
return x+3
result=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(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!
如果你觉得累了没关系,作者写这篇博文可是用了将近一天的时间呢~
我想你甚至可以从名字上猜测数来它是做什么的了:
没错,过滤
def is_odd(n):
return n % 2 == 1
list(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([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_fun
def fun(x):
return x*x
fun(5)
#结果是26
其实作者本人接触函数编程也只有一天,我写python的博客大概也坚持了将近两周,我只是以自己最好理解的方式来整理一下目前我看到的资料。如果有什么错误,欢迎指正~