容器类高阶函数,简化你的Python代码

举报
云上有未来 发表于 2019/08/12 11:37:37 2019/08/12
【摘要】 用Python实现一段代码找出微波C++源码目录中名称重复cpp文件都放置在哪些目录。由于该初学Python,因此仍沿用传统的过程式思维,使用较多for语句处理,造成代码较多不简洁,难于维护和调试。后来一起将代码修改为使用容器类高阶函数后,极大简化了代码,因此在这里对常用高阶函数做个总结。 本文来自作者黄雪飞

1      背景

上周有一个同事找到我,打算用Python实现一段代码,找出微波C++源码目录中名称重复cpp文件都放置在哪些目录。由于该同事初学Python,因此仍沿用传统的过程式思维,使用较多for语句处理,造成代码较多不简洁,难于维护和调试。

后来我和他一起将代码修改为使用容器类高阶函数后,极大简化了代码。因此在这里对常用高阶函数做个总结。

 

2      什么是高阶函数

简单说就是使用函数作为输入参数,或者返回结果为函数的函数,被称为高阶函数。

3      Python容器类高阶函数都有哪些?

Python的容器(Container)有ListSetMapTuple这些容器都支持以下这些高阶函数

可以将这些高阶函数作为基本算子,熟练使用这些算子,可以大大减少过程式的循环操作代码。

 

3.1      map函数

3.1.1        说明

官方api手册定义如下

map(functioniterable...)

Return an iterator that applies function to every item of iterable, yielding the results. 

容器映射,即一个容器中每一个元素通过function运算后,映射成另一个新容器的迭代器。 之所以叫“新”,是因为不会修改原有容器。

1c58c2636f35fc41b8ec_576x336.png@900-0-90-f.png

3.1.2        示例代码

l  将容器中所有元素加1,形成新容器

 

alist = [123]
blist = 
list(map(lambda x: x+1, alist))
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))

 

l  运行结果

b33052636f35fd260d05_466x138.png@900-0-90-f.png

3.1.3        API参考

https://docs.python.org/3/library/functions.html#map

 

3.2      filter函数

3.2.1        说明

filter(functioniterable)

Construct an iterator from those elements of iterable for which function returns true. 

容器元素过滤,即一个容器中每一个元素通过function运算后,将那些返回true的元素生成一个新的容器。

 

92d172636f35fdbe4663_576x336.png@900-0-90-f.png

3.2.2        示例代码

l  过滤容器中所有奇数,形成新容器

 

alist = [123]
blist = 
list(filter(lambda x: x % == 1, alist))
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))

 

l  运行结果

grey.gif

3.2.3        API参考

https://docs.python.org/3/library/functions.html#filter

 

 

 

3.3      reduce函数

3.3.1        说明

functools.reduce(functioniterable[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合并成一个,直到将容器中所有元素合并成一个

421892636f35ff6b2509_576x336.png@900-0-90-f.png

Python2中内置函数reducePython3已经被移动至functools模块。

可以利用reduce,实现内置函数的summaxmin等功能

 

同样类似功能函数还有itertools模块的accumulate,它会输出每个合并步骤的值。

3.3.2        示例代码

l  对容器中所有元素求和、找出所有元素最大值、最小值

from functools import reduce
alist = [123]
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  运行结果

27ddc2636f36004e3dcf_550x264.png@900-0-90-f.png

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=Nonereverse=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值对元素进行排序。

c640c2636f6804018f66_701x336.png@900-0-90-f.png

如果容器存储的元素是对象,可以根据对象的多个属性,轻松实现多属性排序。

3.4.2        示例代码

l  按其负值排序

 

alist = [123]
blist = sorted(alist, key=lambda x: -x)
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))

 

l  运行结果

grey.gif

 

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 in alist:
    print(n, sep=" ",end=" ")
print()
for in blist:
    print(n, sep=" ",end=" ")

 

注:list(map(lambda c: -ord(c), stu.name))  是将姓名逐个字母生成ascii码取反形成list,实现姓名降序

l  运行结果

83d4e2636f3602c4452d_440x89.png@900-0-90-f.png

3.4.4        API参考

https://docs.python.org/3/library/functions.html#sorted

 

3.5      groupby函数

3.5.1        说明

itertools.groupby(iterablekey=None)

创建一个迭代器,返回 iterable 中连续的键和组。key 是一个计算元素键值函数。如果未指定或为 Nonekey缺省为恒等函数(identity function),返回元素不变。一般来说,iterable 需用同一个键值函数预先排序

其中key接受一个函数,容器中每一个元素通过function运算生成Key值,然后按Key值对元素进行分组。注意:容器需要先排序,再分组,且分组指定函数和排序指定函数需要相同。

822292636f6806118b81_1348x336.png@900-0-90-f.png

 

3.5.2        示例代码

l  对数字进行奇偶数分组

from itertools import groupby
alist = [312]
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 in group:
        print(i, end=" ")
    print(")"end=" ")

 

l  运行结果

0ca222636f3604f0ab0f_523x55.png@900-0-90-f.png

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 = [123]
for in alist:
    print( i + 1end=" ")

 

l  运行结果

a3b512636f36057aa4dd_309x103.png@900-0-90-f.png

 

 

3.7      生成式实现的flatmap

3.7.1        说明

Python没有提供迭代器的flatmap功能函数,flatmap即将两级嵌套的容器拍平成一个非嵌套容器。

可以通过生成式实现,语法格式如下:

 

[i for subList in <NestedContainer> for in subList]

 

3.7.2        示例代码

l  将一个两级嵌套容器拍平生成一个容器

 

alist = [[12],[3]]
blist = [i for sublist in alist for in sublist]
print("alist = {0}".format(alist))
print("blist = {0}".format(blist))

 

l  运行结果

2b3092636f3606105772_560x128.png@900-0-90-f.png

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  附代码

 

4324a2636f6808fe8c0f_169x56.png@900-0-90-f.png

l  使用帮助

python find_same_file_name.py -h

c09652636f360757fa5d_731x166.png@900-0-90-f.png

 

l  执行命令样例

python find_same_file_name.py -d F:\mw_git\RTN_IF_codeclub\src\ -e .gitattributes,CMakeLists.txt

987c72636f36082a6c2b_800x566.png@900-0-90-f.png

 

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/


【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。