列表推导和生成器表达式列表推导是一种构建列表的方式,生成器表达式可用于创建任何其他类型的序列。列表理解列表,可以通过多种方式构建:使用一对方括号表示一个空列表:[]。用逗号分隔的项目使用方括号:[a]、[a、b、c]。使用类型构造运算符:list()或list(iterable)。使用列表理解:[xforxiniterable]以上都是生成列表的形式。其中,列表理解更具可读性。列表理解和可读性将方括号和列表理解的使用与以下两个示例进行比较:示例1:将字符串转换为Unicode代码点列表>>>letters="abcdefg">>>codes=[]>>>forletterinletters:...codes.append(ord(letter))...>>>codes[97,98,99,100,101,102,103]示例2:将字符串转换为Unicode代码另一种方式writingbits>>>letters="abcdefg">>>codes=[ord(letter)forletterinletters]>>>codes[97,98,99,100,101,102,103]两者比较,列表理解更具可读性。当然,搞乱列表理解也会产生副作用。作为一般规则,在使用列表推导式创建新列表时,请使它们尽可能短。如果列表理解超过两行,请考虑使用for循环来创建它。但没有硬性要求,选择权在用户手中。变量泄漏在Python2中,列表推导式存在变量泄漏问题。但是在Python3中,这个问题就不会再出现了。Python2列表理解示例:Python2.7.12(默认,2019年10月8日,14:14:10)[GCC5.4.020160609]onlinux2Type“help”、“copyright”、“credits”或“license”以获取更多信息.>>>x="thisword">>>dummy=[xforxin"abc"]>>>x'c'从结果可以看出,x的值被替换了。这是Python3中的代码:Python3.6.5|Anaconda,Inc.|(默认,2018年4月29日,16:14:56)[GCC7.2.0]在linux上键入“help”、“copyright”、“credits”或“license”以获取更多信息。>>>x="thisword">>>dummy=[xforxin"abc"]>>>x'thisword'>>>dummy['a','b','c']的值x的值没有改变,虚拟对象创建成功。这里的过滤器元素尝试与filter()和map()进行比较。使用列表理解结合map/filter创建相同的列表>>>letters="abcdefg">>>match_portion=[ord(letter)forlettersinlettersiford(letter)>100]>>>match_portion[101,102,103]>>>match_portion=list(filter(lambdax:x>100,map(ord,letters)))>>>match_portion[101,102,103]这是两者各自的实现In[4]:%timeit[ord(letter)forletterinlettersiford(letter)>100]764ns±4.36nsperloop(mean±std.dev.of7runs,1000000loopseach)In[5]:%timeitlist(filter(lambdax:x>100,map(ord,letters)))1.37μs±5.37nsperloop(mean±std.dev.of7runs,1000000loopseach)这里是尝试比较运行速度两者中,可以看出,map/filter组合比列表理解慢。map()函数接受两个参数,一个是函数,另一个是Iterable。map依次将传入函数应用于序列的每个元素,并将结果作为新的Iterator返回。filter()函数也接受一个函数和一个序列。与map()不同的是,filter()将传入的函数依次应用到每个元素上,然后根据返回值是True还是False来决定保留还是丢弃该元素。关于map和filter的更详细的讨论将在后面的单独空间中详细阐述。生成器表达式虽然列表推导式可用于初始化元组、数组或其他序列类型,但生成器表达式是更好的选择。因为生成器表达式符合迭代器协议,它一个一个地生成元素,而不是创建一个完整的列表,然后将列表传递给构造函数。两者对比,很明显生成器表达式更节省内存。生成器表达式的语法类似于列表理解,除了方括号被圆括号代替。示例使用生成器表达式初始化元组>>>letters="abcdefg">>>tuple(ord(letter)forletterinletters)(97,98,99,100,101,102,103)注意:如果生成如果说明符expression是函数调用中的唯一参数,因此不需要用额外的括号将它们括起来。>>>tuple(ord(letter)forlettersinletters)(97,98,99,100,101,102,103)>>>tuple((ord(letter)forlettersinletters))(97,98,99,100,101,102,103)具有相同的效果,如果生成器表达式是唯一的参数,则不需要额外的括号。尝试使用生成器表达式来实现笛卡尔积,例如:>>>letters=['a','b','c','d','e','f']>>>nums=['1','2','3']>>>forle_numin('{}{}'.format(le,num)forleinlettersfornuminnums):...print(le_num)。..a1a2a3b1b2b3c1c2...在这里,每次for循环运行时,生成器表达式都会生成一个组合,所以内存不会留下一个组合列表。如果两个列表中的元素数量很大,这里的生成器表达式可以大大减少运行for的开销。这里只是简单介绍一下生成器如何初始化链表外的序列,避免额外的内存占用。生成器的详细工作原理也将在后面单独的篇幅进行讲解。参考来源DavidM.Beazley;BrianK.Jones.PythonCookbook,3rdEditioni.O'ReillyMedia.2013."4.Built-inTypes".docs.python.org.Retrieved14January2020LiaoXuefeng."PythonTutorial".liaoxuefeng.com.[2020-01-17]。欢迎关注微信公众号《书所集录》
