🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 16.3. 重识列表过滤 你已经熟识了[应用列表解析来过滤列表](../power_of_introspection/filtering_lists.html "4.5. 过滤列表")。这里介绍的是达到相同效果的另一种令很多人感觉清晰的实现方法。 Python 有一个内建 `filter` 函数,它接受两个参数:一个函数和一个列表,返回一个列表。\[12\] 作为第一个参数传递给 `filter` 的函数本身应接受一个参数,`filter` 返回的列表将会包含被传入列表参数传递给 `filter` 所有可以令函数返回真 (true) 的元素。 都明白了吗?并没有听起来那么难。 ## 例 16.7. `filter` 介绍 ``` >>> def odd(n): ... return n % 2 ... >>> li = [1, 2, 3, 5, 9, 10, 256, -3] >>> filter(odd, li) [1, 3, 5, 9, -3] >>> [e for e in li if odd(e)] >>> filteredList = [] >>> for n in li: ... if odd(n): ... filteredList.append(n) ... >>> filteredList [1, 3, 5, 9, -3] ``` | | | | --- | --- | | \[1\] | `odd` 使用内建的取模 (mod) 函数 “`%`” 对于为奇数的 `n` 返回 `1`;为偶数的返回 `0`。 | | \[2\] | `filter` 接受两个参数:一个函数 (`odd`) 和一个列表 (`li`)。它依列表循环为每个元素调用 `odd` 函数。如果 `odd` 返回的是真 (记住,Python 认为所有非零值为真),则该元素被放在返回列表中,如若不然则被过滤掉。结果是一个只包含原列表中奇数的列表,出现顺序则和原列表相同。 | | \[3\] | 你可以通过遍历的方式完成相同的工作,正如在 [第 4.5 节 “过滤列表”](../power_of_introspection/filtering_lists.html "4.5. 过滤列表") 中看到的。 | | \[4\] | 你可以通过 `for` 循环的方式完成相同的工作。取决于你的编程背景,这样也许更“直接”,但是像 `filter` 函数这样的实现方法更清晰。不但编写简单,而且易于读懂。`for` 循环就好比近距离的绘画:你可以看到所有的细节,但是或许你应该花几秒时间退后几步看一看图画的全景:“啊,你仅仅是要过滤列表!” | ## 例 16.8. `regression.py` 中的 `filter` ``` files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = filter(test.search, files) ``` | | | | --- | --- | | \[1\] | 正如你在 [第 16.2 节 “找到路径”](finding_the_path.html "16.2. 找到路径") 中看到的,`path` 可能包括正在运行脚本的完全或者部分路径名,或者当脚本运行自当前目录时包含一个空的字符串。任何一种情况下,`files` 都会获得正运行脚本所在目录的文件名。 | | \[2\] | 这是一个预编译的正则表达式。正如你在 [第 15.3 节 “重构”](../refactoring/refactoring.html "15.3. 重构")中看到的,如果你需要反复使用同一个正则表达式,你应该编译它已获得更快的性能。编译后的对象将含有接受一个待寻找字符串作为参数的 `search` 方法。如果这个正则表达式匹配字符串,`search` 方法返回一个包含正则表达式匹配信息的 `Match` 对象;否则返回 `None`,这是 Python 空 (null) 值。 | | \[3\] | 对于 `files` 列表中的每个元素,你将会调用正则表达式编译对象 `test` 的 `search` 方法。如果正则表达匹配,方法将会返回一个被 Python 认定为真 (true) 的 `Match` 对象;如果正则表达不匹配,`search` 方法将会返回被认定为假 (false) 的 `None`,元素将被排除。 | **历史注释. **Python 2.0 早期的版本不包含 [列表解析](../native_data_types/mapping_lists.html "3.6. 映射 list"),因此不能 [以列表解析方式过滤](../power_of_introspection/filtering_lists.html "4.5. 过滤列表"),`filter` 函数是当时唯一的方法。即便是在引入列表解析的 2.0 版,有些人仍然钟情于老派的 `filter` (和这章稍后将见到的它的伴侣函数 `map` )。两种方法并存于世,使用哪种方法只是风格问题,`map` 和 `filter` 将在未来的 Python 版本中被废止的讨论尚无定论。 ## 例 16.9. 以列表解析法过滤 ``` files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = [f for f in files if test.search(f)] ``` | | | | --- | --- | | \[1\] | 这种方法将完成和 `filter` 函数完全相同的工作。哪种方法更清晰完全取决于你自己。 | ## Footnotes \[12\] 从技术层面上讲,`filter` 的第二个参数可以是任意的序列,包括列表、元组以及定义了 `__getitem__` 特殊方法而能像列表一样工作的自定义类。在可能情况下,`filter` 会返回与输入相同的数据类型,也就是过滤一个列表返回一个列表,过滤一个元组返回一个元组。