4.5. 过滤列表
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 4.5. 过滤列表

如你所知，Python 具有通过列表解析 (第 3.6 节 “映射 list”) 将列表映射到其它列表的强大能力。这种能力同过滤机制结合使用，使列表中的有些元素被映射的同时跳过另外一些元素。

过滤列表语法：

    [mapping-expression for element in source-list if filter-expression]

这是你所知所爱的列表解析的扩展。前三部分都是相同的；最后一部分，以 `if` 开头的是过滤器表达式。过滤器表达式可以是返回值为真或者假的任何表达式 (在 Python 中是几乎任何东西)。任何经过滤器表达式演算值为真的元素都可以包含在映射中。其它的元素都将忽略，它们不会进入映射表达式，更不会包含在输出列表中。

### 例 4.14. 列表过滤介绍

    >>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
    >>> [elem for elem in li if len(elem) > 1]
    ['mpilgrim', 'foo']
    >>> [elem for elem in li if elem != "b"]
    ['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
    >>> [elem for elem in li if li.count(elem) == 1]
    ['a', 'mpilgrim', 'foo', 'c']

| 这里的映射表达式很简单 (只是返回每个元素的值)，所以请把注意力集中到过滤器表达式上。由于 Python 会遍历整个列表，它将对每个元素执行过滤器表达式。如果过滤器表达式演算值为真，该元素就会被映射，同时映射表达式的结果将包含在返回的列表中。这里，你过滤掉了所有单字符的字符串，留下了一个由长字符串构成的列表。
| 这里你过滤掉了一个特定值 `b`。注意这个过滤器会过滤掉所有的 `b`，因为每次取出 `b`，过滤表达式都将为假。
| `count` 是一个列表方法，返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素，返回一个只包含了在原始列表中有着唯一值拷贝的列表。但并非如此，因为在原始列表中出现两次的值 (在本例中，`b` 和 `d`) 被完全剔除了。从一个列表中排除重复值有多种方法，但过滤并不是其中的一种。

回到 `apihelper.py` 中的这一行：

        methodList = [method for method in dir(object) if callable(getattr(object, method))]

这行看上去挺复杂――确实也很复杂――但是基本结构都还是一样的。整个过滤表达式返回一个列表，并赋值给 `methodList` 变量。表达式的前半部分是列表映射部分。映射表达式是一个和遍历元素相同的表达式，因此它返回每个元素的值。``dir`(`object`)` 返回 `object` 对象的属性和方法列表――你正在映射的列表。所以唯一新出现的部分就是在 `if` 后面的过滤表达式。

过滤表达式看上去很恐怖，其实不是。你已经知道了 `callable`、`getattr` 和 `in`。正如你在前面的部分中看到的，如果 `object` 是一个模块，并且 `method` 是上述模块中某个函数的名称，那么表达式 `getattr(object, method)` 将返回一个函数对象。

所以这个表达式接收一个名为 `object` 的对象，然后得到它的属性、方法、函数和其他成员的名称列表，接着过滤掉我们不关心的成员。执行过滤行为是通过对每个属性/方法/函数的名称调用 `getattr` 函数取得实际成员的引用，然后检查这些成员对象是否是可调用的，当然这些可调用的成员对象可能是方法或者函数，同时也可能是内置的 (比如列表的 `pop` 方法) 或者用户自定义的 (比如 `odbchelper` 模块的 `buildConnectionString` 函数)。这里你不用关心其它的属性，如内置在每一个模块中的 `__name__` 属性。

### 进一步阅读

- Python Tutorial 讨论了使用内置 `filter` 函数过滤列表的另一种方式。