或者,如果我们愿意为了简洁而牺牲一些可读性,那么可以写成:
- print pipeline_each(bands, [call(lambda x: 'Canada', 'country'),
- call(lambda x: x.replace('.', ''), 'name'),
- call(str.title, 'name')])
call() 的实现代码:
- def assoc(_d, key, value):
- from copy import deepcopy
- d = deepcopy(_d)
- d[key] = value
- return d
-
- def call(fn, key):
- def apply_fn(record):
- return assoc(record, key, fn(record.get(key)))
- return apply_fn
上面的实现中有不少内容要讲,让我们一点一点地来说明:
call() 是一个高阶函数。高阶函数是指将函数作为参数,或返回函数。或者,就像 call() ,输入和返回2者都是函数。
apply_fn() 看起来与三个转换函数非常相似。输入一个记录(一个乐队), record[key] 是查找出值;再以值为参数调用 fn ,将调用结果赋值回记录的副本;最后返回副本。
call() 不做任何实际的事。而是调用 apply_fn() 时完成需要做的事。在上面的示例的 pipeline_each() 中,一个 apply_fn() 实例会设置传入乐队的 'country' 成 'Canada' ;另一个实例则将传入乐队的名字转成大写。
- 当运行一个
apply_fn() 实例, fn 和 key 2个变量并没有在自己的作用域中,既不是 apply_fn() 的参数,也不是本地变量。但2者仍然可以访问。
- 当定义一个函数时,会保存这个函数能闭包进来(
close over )的变量引用:在这个函数外层作用域中定义的变量。这些变量可以在该函数内使用。
- 当函数运行并且其代码引用变量时,
Python 会在本地变量和参数中查找变量。如果没有找到,则会在保存的引用中查找闭包进来的变量。就在这里,会发现 fn 和 key 。
- 在
call() 代码中没有涉及乐队列表。这是因为 call() ,无论要处理的对象是什么,可以为任何程序生成管道函数。函数式编程的一大关注点就是构建通用的、可重用的和可组合的函数所组成的库。
完美!闭包( closure )、高阶函数以及变量作用域,在上面的几段代码中都涉及了。嗯,理解完了上面这些内容,是时候来个驴肉火烧打赏一下自己。 :sushi:
最后还差实现一段处理乐队的逻辑:删除除名字和国家之外的内容。 extract_name_and_country() 可以把这些信息提取出来:
- def extract_name_and_country(band):
- plucked_band = {}
- plucked_band['name'] = band['name']
- plucked_band['country'] = band['country']
- return plucked_band
-
- print pipeline_each(bands, [call(lambda x: 'Canada', 'country'),
- call(lambda x: x.replace('.', ''), 'name'),
- call(str.title, 'name'),
- extract_name_and_country])
-
- # => [{'name': 'Sunset Rubdown', 'country': 'Canada'},
- # {'name': 'Women', 'country': 'Canada'},
- # {'name': 'A Silver Mt Zion', 'country': 'Canada'}]
extract_name_and_country() 本可以写成名为 pluck() 的通用函数。 pluck() 使用起来是这个样子:
【译注】作者这里用了虚拟语气『*本*可以』。 (编辑:晋中站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|