<< >>

diveintopython.org |

Python for experienced programmers

## 2.6. 过滤列表

你已经知道了，Python拥有强大的映射列表到其它列表的能力。它可以同一种过滤机制合并，即列表中的某此元素被映射，而其它的被完全忽略。

例 2.14. 列表过滤语法

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

前三分之二的表达式应该看上去熟悉了，因为它与列表映射有着相同的结构。最后一部分，以 `if` 开始的，就是过滤表达式。一个过滤表达式可以是任意地计算真假值的表达式(这在Python中可能是几乎任何东西)。任何对于过滤表达式计算出真值的元素将包括在映射中。其它所有元素被忽略掉，所以它们不会进入映射表达式，并且也不被包括在输出列表中。

例 2.15. 列表过滤介绍

    >>> 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`)被完全排除了。存在从一个列表排除重复值的方法，但是过滤不是解决办法。

例 2.16. 在 `apihelper.py` 中过滤列表

        typeList = (BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, ClassType)
        methodList = [method for method in dir(object) if type(getattr(object, method)) in typeList]

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

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

所以这个表达式接收一个名为 `object` 的对象，得到它的属性，方法，和一些其它东西的名字列表，然后过滤那个列表来除掉所有我们不关心的东西。我们执行过滤是通过得到每个属性/方法/函数的名字，然后通过 `getattr` 函数得到指向实际东西的引用。然后我们用 `type` 函数来检查对象的类型，接着查看是否那个类型是我们所关心的东西之一。特别地，我们关心方法和函数，内置的(如一个列表的 `pop` 方法)和用户自定义的(如 `odbchelper` 模块中的 `buildConnectionString` 函数)。我们不关心其它的属性，如内置在每一个模块中的 `__name__` 属性。

你可能已经注意到过滤表达式也包括了类型为 `ClassType` 的对象。现在不要对此担心，当我们进行到第三章中的面向对象概念时，我们将讨论Python的类(译注：原文为“Don't worry about this for now; we'll discuss Python classes ad nauseum when we get into object-oriented concepts in chapter 3.”，不知道 ad nauseum 是什么意思。)。

进一步阅读 |

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

« 使用 getattr 得到对象各种引用 | and-or 技巧 »