16.4. 关联已访问列表

你对使用 列表遍历 将列表关联起来的做法已经熟知。 另一种方法可以完成同样的工作:使用内建 map 函数。 它的工作机理和 filter 函数类似。

例 16.10. 介绍 map

>>> def double(n):
...     return n*2
...     
>>> li = [1, 2, 3, 5, 9, 10, 256, -3]
>>> map(double, li)                       1
[2, 4, 6, 10, 18, 20, 512, -6]
>>> [double(n) for n in li]               2
[2, 4, 6, 10, 18, 20, 512, -6]
>>> newlist = []
>>> for n in li:                          3
...     newlist.append(double(n))
...     
>>> newlist
[2, 4, 6, 10, 18, 20, 512, -6]
1 map 接受一个函数和一个列表作为参数,[8] 并以列表中每个元素顺序地调用函数返回一个新的列表。 在这个例子中,函数仅仅是将每个元素乘以2。
2 使用列表遍历的方法你可以做到相同的事情。 列表遍历是在 Python 2.0版时被引入的,map 便从此永远盘桓。
3 你如果坚持以 Visual Basic 程序员而自居,通过 for 循环的方法完成相同的任务也完全可以。

例 16.11. map 与混合数据类型的列表

>>> li = [5, 'a', (2, 'b')]
>>> map(double, li)                       1
[10, 'aa', (2, 'b', 2, 'b')]
1 作为一个旁注,我想指出只要提供的那个函数能够正确处理各种数据类型, map 对于混合数据类型列表的处理同样出色。 在这里,这个 double 函数仅仅是将给定参数乘以 2 , Python 根据参数的数据类型决定 正确操作 的方法。 对整数而言,这意味着乘 2 ;对字符串而言,意味着把自身和自身连接;对于元组,意味着构建一个包括原始元组全部元素和原始元组组合在一起的新元组。

好了,玩够了。让我们来看一些真实代码。

例 16.12. regression.py 中的 map

    filenameToModuleName = lambda f: os.path.splitext(f)[0] 1
    moduleNames = map(filenameToModuleName, files)          2
1 正如你在 第 4.7 节 “使用 lambda 函数” 中所见, lambda 定义一个内嵌函数。 也正如你在 例 6.17 “分割路径名” 中所见, os.path.splitext 接受一个文件名并返回一个元组 name, extension。因此 filenameToModuleName 是一个接受文件名并提出文件扩展名而只返回文件名称的函数。
2 调用它 map 接受files列出的所有文件名,把它传递给 filenameToModuleName 函数,并且返回每个函数调用结果所组成的列表。 换句话说,你剔除掉文件名的扩展名,并将剔除后的文件名存于 moduleNames 之中。

如你在本章剩余部分将看到的,你可以将这种数据中心思想扩展应用到定义和执行一个容纳来自很多单个测试套件的测试的一个测试套件的最终目标。

Footnotes

[8] 同前,我需要指出 map 可以接受一个列标、元组,或者一个像序列一样的对象。参见前面的关于 filter 的脚注。