打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Python编程:内置函数map的深入剖析与实践(案例参考)
userphoto

2022.11.14 新疆

关注

前言

各位读者朋友好,本头条号@传新视界接下来将写几篇有关Python常用内置函数的内容。我们知道Python随身发布的类库模块是非常优秀的,如无特别需要,很多任务都可以不引入外部第三库包就可以完成,所以学习研究Python自身的标准库是非常值得的。

本篇就主要来探究一下map函数的相关情况——我这里还是结合代码来介绍,以便你上手操作来加深理解和应用。开始——记得点赞 + 关注@传新视界,前进不迷路

Python内置函数map实战应用参考示例

map函数简介

使用语法为:map(function, iterable,…)。使用该函数时,你可以直接查阅官方文档中对内置函数map的使用说明:

Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted.

意思是说,map函数返回的结果是个迭代器,该迭代器对每一个参数可迭代对象的项(元素)应用相应的函数,并产生相应结果。如果传递了额外的可迭代参数,作为参数的函数也必须接受同样多的参数,且并行对所有可迭代对象中的项应用于函数。对于有多个可迭代对象的,迭代器在最短可迭代对象耗尽时停止。

也可以可以通过help函数在IDLE模式下查看内置说明:

查看map说明

很显然,map函数是来源于内置模块builtins中的同名map类。该类实现了迭代器协议,所以它是个迭代器类,且有个同名的函数map。经过Python内部的包装,使我们可以直接以map函数的形式直接加以使用。

这里我们只关注官方的函数文档描述。第一个参数须为有效函数,包括lambda函数。后面的参数可跟多个可迭代对象,也可为单个可迭代对象(单可迭代比较简单)。

应用实践

下面通过示例来进一步研究map函数的应用。

1)使用一个lambda函数,它接受数量可变的位置参数,并将它们作为元组返回(下面的程序可以直接在IDLE下分别输入运行):

#map函数应用#示例-1:传入一个可迭代对象m1 = map(lambda *a:a,range(3))print(m1) #m为可迭代的map对象print(list(m1)) #可迭代对象转换为list#示例-2:传入两个可迭代对象m2 = map(lambda *a:a,range(3),'abc')print(m2) #m2为可迭代的map对象print(list(m2)) #可迭代对象转换为list#示例-3:传入3个可迭代对象m3 = map(lambda *a:a,range(3),'abc',range(4,7))print(m3) #m2为可迭代的map对象print(list(m3)) #可迭代对象转换为list#示例-4:传入两个可迭代对象,且有最短的空元组m4 = map(lambda *a:a,(),'abc')print(m4) #m为可迭代的map对象print(list(m4)) #可迭代对象转换为list#示例-4:传入两个可迭代对象,且(1,2)最短m5 = map(lambda *a:a,(1,2),'abc')print(m5) #m为可迭代的map对象print(list(m5)) #可迭代对象转换为list#示例-6:传入两个可迭代对象,且最短的是'abc'm6 = map(lambda *a:a,(1,2,3,4),'abc')print(m6) #m6为可迭代的map对象print(list(m6)) #可迭代对象转换为list

运行上面的程序,观察所输出结果类似如下:

<map object at 0x000002344DF47BB0>

[(0,), (1,), (2,)]

<map object at 0x000002344DF47B50>

[(0, 'a'), (1, 'b'), (2, 'c')]

<map object at 0x000002344DF47AC0>

[(0, 'a', 4), (1, 'b', 5), (2, 'c', 6)]

<map object at 0x000002344DF47A90>

[]

<map object at 0x000002344DF47A00>

[(1, 'a'), (2, 'b')]

<map object at 0x000002344DF47970>

[(1, 'a'), (2, 'b'), (3, 'c')]

在前面的代码中,可以看到为什么必须将调用结果用list(…)处理。因为如果没有它,我们将得到map对象的字符串表示,这在上下文中并没啥用,因为看不到相应的内容,不知道map处理的是个啥结果。

你可能也注意到每个可迭代对象的元素是如何应用于函数的:首先是每个可迭代对象的第一个元素,然后是每个可迭代对象的第二个元素,以此类推。还要注意到map()会在调用函数时,在最短的可迭代对象耗尽时会停止。这实际上是一个非常好的行为特性——它既不会强迫我们将所有的可迭代对象都调整为相同的长度,而长度都相同时,它也不会中断执行。

2)自定义函数作为参数传入map函数。我们 再来看个自定义函数,使用map函数的结果来输出符号三角形(一定注意代码):

#自定义函数,参数为对应可迭代对象中的元素项#ln为整数,表示行;sym为每行指定的符号def symbolTrian(ln,sym):    '''ln行号1...n;sym:每行显示的符号'''    return str(ln)+'. '+sym*lnprint('++'*20)for ln in list(map(symbolTrian,range(1,5),'~~~~~~')):    print(ln)

上述程序输出的结果类似如下:

++++++++++++++++++++++++++++++++++++++++

1. ~

2. ~~

3. ~~~

4. ~~~~

当你必须对一个或多个对象集合应用相同的函数时,Map()非常有用。作为一个更有趣的例子,让我们看看装饰-排序-非装饰风格(decorate-sort-undecorate,也称为Schwartzian变换)处理示例。在较早的Python版本中,当排序不支持使用key function时,这是一种非常流行的技术。如今,它已经不那么常用了,但这是一个很酷的技巧,偶尔还是会派上用场。

我们来在下面的例子中看看它的变化:我们想要按学生累积的学分总和降序排序,这样就可以让成绩最好的学生排在第0位。我们编写一个函数来生成一个装饰对象,然后进行排序,然后进行非装饰。每个学生有三个(可能不同的)科目的学分。在这个上下文中,修饰一个对象意味着转换它,要么向它添加额外的数据,要么将其放入另一个对象中,以一种允许我们能够按照我们想要的方式对原始对象进行排序的方式。注意:这种技术与Python装饰器无关,我们前面已经对装饰器进行了讨论介绍。

排序之后,我们恢复装饰对象,从它们获得原始对象,这种处理被称为非装饰(即取消装饰处理形态)。

如果上面的描述还不太清楚,请结合代码多看两遍。代码清单如下:

#decorate-sort-undecorate (即Schwartzian transform).# 即Schwartzian转换处理students = [ dict(id=0, credits=dict(math=9, physics=6, history=7)), dict(id=1, credits=dict(math=6, physics=7, latin=10)), dict(id=2, credits=dict(history=8, physics=9, chemistry=10)), dict(id=3, credits=dict(math=5, physics=5, geography=7)), ]#列表的每一项即为一个字典表示的studentdef decorate(student): # 用student字典创建一个二元元组 (sum of credits, student) return (sum(student['credits'].values()), student)def undecorate(decorated_student): # 抛弃装饰处理,获取原始的学生信息,但为已排序的原始学生信息 return decorated_student[1]decStudents = sorted(map(decorate, students), reverse=True)print('装饰转换排序(降序)信息:')for s in decStudents: print(s)print('取消装饰转换后原始信息(有序):')undecStudents = list(map(undecorate, decStudents))for s in undecStudents: print(s)

运行程序输出结果类似如下:

装饰转换排序(降序)信息:

(27, {'id': 2, 'credits': {'history': 8, 'physics': 9, 'chemistry': 10}})

(23, {'id': 1, 'credits': {'math': 6, 'physics': 7, 'latin': 10}})

(22, {'id': 0, 'credits': {'math': 9, 'physics': 6, 'history': 7}})

(17, {'id': 3, 'credits': {'math': 5, 'physics': 5, 'geography': 7}})

取消装饰转换后原始信息(有序):

{'id': 2, 'credits': {'history': 8, 'physics': 9, 'chemistry': 10}}

{'id': 1, 'credits': {'math': 6, 'physics': 7, 'latin': 10}}

{'id': 0, 'credits': {'math': 9, 'physics': 6, 'history': 7}}

{'id': 3, 'credits': {'math': 5, 'physics': 5, 'geography': 7}}

结合代码和输出结果,应该不难理解。但关于排序部分需要注意的一点是,当两个或两个以上的学生有相同的总和时会发生什么。排序算法通过相互比较学生对象来对元组进行排序。这没有任何意义,在更复杂的情况下,可能会导致不可预测的结果,甚至是错误。如果想确保避免这个问题,一个简单的解决方案是创建一个三元组而不是二元组,将学分的总和放在第一个位置,学生对象在学生列表中的位置或id放在第二个位置,学生对象本身放在第三个位置。通过这种方式(即decorate返回的结果元组中间增加一个id/位置项),此时如果积分和相同,元组将根据位置或id进行排序,位置总是不同的,因此足以解决任何对元组之间的排序问题。

本文小结

本文主要探讨了Python内置函数map的应用情况,既要理解其含义,也要能灵活掌握应用场景,特别要注意当传入多个可迭代对象时处理的模式机制,更要深入理解函数参数所应有的目标对象是可迭代对象中的元素项,以及和map函数返回值——可迭代对象的转化处理等。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Python3中一些高阶函数map、reduce、filter详解及示例
[python] Python map函数总结
Python中强大的函数: map(), filter()和 reduce()
Python入门教程:内置函数—Map、Reduce、Filter
python小课堂28
[编程基础] Python lambda函数总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服