您当前位置:首页 > 深入 Python > 函数式编程 > 再次探讨列表过滤 | << >> | ||||
深入 Python从 Python 新手到专家 |
您已经熟悉使用列表推导式过滤列表。还有一种方法可以实现同样的功能,有些人认为这种方法更具表达力。
Python 有一个内置的 filter 函数,它接受两个参数,一个函数和一个列表,并返回一个列表。[7] 作为第一个参数传递给 filter 的函数本身必须接受一个参数,并且 filter 返回的列表将包含传递给 filter 的列表中所有使传递给 filter 的函数返回 true 的元素。
明白了吗?这并不像听起来那么难。
>>> 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]
![]() |
odd 使用内置的模运算符 “%” 来返回 True(如果 n 为奇数)和 False(如果 n 为偶数)。 |
![]() |
filter 接受两个参数,一个函数 (odd) 和一个列表 (li)。它循环遍历列表,并使用每个元素调用 odd。如果 odd 返回一个真值(请记住,在 Python 中,任何非零值都是真),则该元素将包含在返回的列表中,否则将被过滤掉。结果是一个列表,其中只包含原始列表中的奇数,顺序与它们在原始列表中出现的顺序相同。 |
![]() |
您可以使用列表推导式完成相同的操作,如您在第 4.5 节“过滤列表”中所见。 |
![]() |
您也可以使用 for 循环完成相同的操作。根据您的编程背景,这可能看起来更“直接”,但像 filter 这样的函数更具表达力。不仅更容易编写,也更容易阅读。阅读 for 循环就像站得太靠近一幅画;您看到了所有的细节,但可能需要几秒钟才能后退一步,看到更大的图景:“哦,您只是在过滤列表!” |
files = os.listdir(path)test = re.compile("test\.py$", re.IGNORECASE)
files = filter(test.search, files)
![]() |
如您在第 16.2 节“查找路径”中所见,path 可能包含当前运行脚本目录的完整或部分路径名,如果脚本是从当前目录运行的,则可能包含一个空字符串。无论哪种方式,files 最终都将包含与您正在运行的脚本位于同一目录中的文件名称。 |
![]() |
这是一个编译后的正则表达式。如您在第 15.3 节“重构”中所见,如果您要反复使用同一个正则表达式,则应该编译它以提高性能。编译后的对象有一个 search 方法,该方法接受一个参数,即要搜索的字符串。如果正则表达式与字符串匹配,则 search 方法返回一个包含有关正则表达式匹配信息的 Match 对象;否则,它返回 None,即 Python 中的空值。 |
![]() |
对于 files 列表中的每个元素,您将调用已编译的正则表达式对象 test 的 search 方法。如果正则表达式匹配,则该方法将返回一个 Match 对象,Python 认为它是真,因此该元素将包含在 filter 返回的列表中。如果正则表达式不匹配,则 search 方法将返回 None,Python 认为它是假,因此该元素将不会包含在内。 |
历史注释。 2.0 之前的 Python 版本没有列表推导式,因此您无法使用列表推导式进行过滤;filter 函数是当时唯一的选择。即使在 2.0 版本中引入了列表推导式,有些人仍然更喜欢旧式的 filter(及其配套函数 map,您将在本章后面看到)。目前这两种技术都有效,因此使用哪一种取决于您的风格。有人讨论说,map 和 filter 可能会在未来的 Python 版本中被弃用,但尚未做出决定。
files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = [f for f in files if test.search(f)]
[7] 从技术上讲,filter 的第二个参数可以是任何序列,包括列表、元组和通过定义 __getitem__ 特殊方法来模拟列表行为的自定义类。如果可能,filter 将返回与您提供的相同的数据类型,因此过滤列表将返回列表,但过滤元组将返回元组。
<< 查找路径 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
再次探讨列表映射 >> |