容器类高阶函数,简化你的Python代码
1 背景
上周有一个同事找到我,打算用Python实现一段代码,找出微波C++源码目录中名称重复cpp文件都放置在哪些目录。由于该同事初学Python,因此仍沿用传统的过程式思维,使用较多for语句处理,造成代码较多不简洁,难于维护和调试。
后来我和他一起将代码修改为使用容器类高阶函数后,极大简化了代码。因此在这里对常用高阶函数做个总结。
2 什么是高阶函数
简单说就是使用函数作为输入参数,或者返回结果为函数的函数,被称为高阶函数。
3 Python容器类高阶函数都有哪些?
Python的容器(Container)有List、Set、Map、Tuple,这些容器都支持以下这些高阶函数。
可以将这些高阶函数作为基本算子,熟练使用这些算子,可以大大减少过程式的循环操作代码。
3.1 map函数
3.1.1 说明
官方api手册定义如下
map(function, iterable, ...)
Return an iterator that applies function to every item of iterable, yielding the results.
容器映射,即一个容器中每一个元素通过function运算后,映射成另一个新容器的迭代器。 之所以叫“新”,是因为不会修改原有容器。
3.1.2 示例代码
l 将容器中所有元素加1,形成新容器
alist = [1, 2, 3]
blist = list(map(lambda x: x+1, alist))
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))
l 运行结果
3.1.3 API参考
https://docs.python.org/3/library/functions.html#map
3.2 filter函数
3.2.1 说明
filter(function, iterable)
Construct an iterator from those elements of iterable for which function returns true.
容器元素过滤,即一个容器中每一个元素通过function运算后,将那些返回true的元素生成一个新的容器。
3.2.2 示例代码
l 过滤容器中所有奇数,形成新容器
alist = [1, 2, 3]
blist = list(filter(lambda x: x % 2 == 1, alist))
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))
l 运行结果
3.2.3 API参考
https://docs.python.org/3/library/functions.html#filter
3.3 reduce函数
3.3.1 说明
functools.reduce(function, iterable[, initializer])
Apply function of two arguments cumulatively to the items of sequence, from left to right, so as to reduce the sequence to a single value.
容器中每两个元素通过function合并成一个,直到将容器中所有元素合并成一个
Python2中内置函数reduce,Python3已经被移动至functools模块。
可以利用reduce,实现内置函数的sum、max、min等功能
同样类似功能函数还有itertools模块的accumulate,它会输出每个合并步骤的值。
3.3.2 示例代码
l 对容器中所有元素求和、找出所有元素最大值、最小值
from functools import reduce
alist = [1, 2, 3]
sum = reduce(lambda x, y: x + y, alist)
max = reduce(lambda x, y: x if x > y else y, alist)
min = reduce(lambda x, y: x if x < y else y, alist)
print("alist = {0}".format(alist))
print("sum = {0}".format(sum))
print("max = {0}".format(max))
print("min = {0}".format(min))
l 运行结果
3.3.3 API参考
https://docs.python.org/3/library/functools.html#functools.reduce
https://docs.python.org/3/library/itertools.html#itertools.accumulate
3.4 sorted函数
3.4.1 说明
sorted(iterable, *, key=None, reverse=False)
Return a new sorted list from the items in iterable.
key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower). The default value is None (compare the elements directly).
其中key接受一个函数,容器中每一个元素通过function运算生成Key值,然后按Key值对元素进行排序。
如果容器存储的元素是对象,可以根据对象的多个属性,轻松实现多属性排序。
3.4.2 示例代码
l 按其负值排序
alist = [1, 2, 3]
blist = sorted(alist, key=lambda x: -x)
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))
l 运行结果
3.4.3 示例代码
l 按Student的年龄升序排序,年龄相同则按姓名降序排序
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "({0}, {1})".format(self.name, self.age)
alist = [Student("Tom", 11), Student("Jim", 10), Student("George", 11)]
blist = sorted(alist, key=lambda stu: (stu.age, list(map(lambda c: -ord(c), stu.name))))
for n in alist:
print(n, sep=" ",end=" ")
print()
for n in blist:
print(n, sep=" ",end=" ")
注:list(map(lambda c: -ord(c), stu.name)) 是将姓名逐个字母生成ascii码取反形成list,实现姓名降序
l 运行结果
3.4.4 API参考
https://docs.python.org/3/library/functions.html#sorted
3.5 groupby函数
3.5.1 说明
itertools.groupby(iterable, key=None)
创建一个迭代器,返回 iterable 中连续的键和组。key 是一个计算元素键值函数。如果未指定或为 None,key缺省为恒等函数(identity function),返回元素不变。一般来说,iterable 需用同一个键值函数预先排序。
其中key接受一个函数,容器中每一个元素通过function运算生成Key值,然后按Key值对元素进行分组。注意:容器需要先排序,再分组,且分组指定函数和排序指定函数需要相同。
3.5.2 示例代码
l 对数字进行奇偶数分组
from itertools import groupby
alist = [3, 1, 2]
keyFun = lambda x: x % 2
blist = groupby(sorted(alist, key=keyFun), keyFun)
print("alist = {0}".format(alist))
print("blist = ", end="")
for key, group in blist:
print("( key = {0} group = ".format(key), end= "")
for i in group:
print(i, end=" ")
print(")", end=" ")
l 运行结果
3.5.3 API参考
https://docs.python.org/zh-cn/3/library/itertools.html#itertools.groupby
3.6 语法层面的foreach
3.6.1 说明
Python语法层面就支持foreach,语法格式如下
for <ver> in <iterable>:
<statements>
3.6.2 示例代码
l 打印所有元素成一行,空格分隔
alist = [1, 2, 3]
for i in alist:
print( i + 1, end=" ")
l 运行结果
3.7 生成式实现的flatmap
3.7.1 说明
Python没有提供迭代器的flatmap功能函数,flatmap即将两级嵌套的容器拍平成一个非嵌套容器。
可以通过生成式实现,语法格式如下:
[i for subList in <NestedContainer> for i in subList]
3.7.2 示例代码
l 将一个两级嵌套容器拍平生成一个容器
alist = [[1, 2],[3]]
blist = [i for sublist in alist for i in sublist]
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))
l 运行结果
3.7.3 参考
生成式
https://www.cnblogs.com/wj-1314/p/8490822.html
4 应用例子
4.1 找出一个目录下的同名文件,打印其路径
l 部分代码如下:
……
# 过滤掉不需要文件
if options.excludefiles:
excludeFilesFun = partial(excludeFiles, options.excludefiles)
fileAndDirTuples = filter(excludeFilesFun, fileAndDirTuples)
# 按文件名分组
fileAndDirTuples = sorted(fileAndDirTuples, key=lambda fileAndDir: fileAndDir[0])
groupedByFileName = groupby(fileAndDirTuples, key=lambda fileAndDir: fileAndDir[0])
……
l 附代码
l 使用帮助
python find_same_file_name.py -h
l 执行命令样例
python find_same_file_name.py -d F:\mw_git\RTN_IF_codeclub\src\ -e .gitattributes,CMakeLists.txt
5 其他操作容器的函数
还有些容器操作函数,虽然不是高阶函数,但也比较常用
5.1 容器元素配对
zip_longest:容器元素配对
5.2 排列、组合、笛卡尔积
product:笛卡尔积
combinations: 排列
combinations_with_replacement: 组合
5.3 API参考
https://docs.python.org/zh-cn/3/library/itertools.html
6 参考资料
函数式编程的一些概念
https://adispring.github.io/2017/12/04/Functions-in-Functional-Programming/
- 点赞
- 收藏
- 关注作者
评论(0)