4.8. 全部放在一起
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.8. 全部放在一起

最后一行代码是唯一还没有解释过的，它完成全部的工作。但是现在工作已经简单了，因为所需要的每件事都已经按照需求建立好了。所有的多米诺骨牌已经就位，到了将它们推倒的时候了。

下面是 `apihelper.py` 的关键

        print "\n".join(["%s %s" %
                          (method.ljust(spacing),
                           processFunc(str(getattr(object, method).__doc__)))
                         for method in methodList])

注意这是一条命令，被分隔成了多行，但是并没有使用续行符 (`\`)。还记得我说过一些表达式可以分割成多行而不需要使用反斜线吗？列表解析就是这些表达式之一，因为整个表达式包括在方括号里。

现在，让我们从后向前分析。

    for method in methodList

告诉我们这是一个列表解析。如你所知 `methodList` 是 `object` 中所有你关心的方法的一个列表。所以你正在使用 `method` 遍历列表。

### 例 4.22. 动态得到 `doc string`

    >>> import odbchelper
    >>> object = odbchelper
    >>> method = 'buildConnectionString'
    >>> getattr(object, method)
    <function buildConnectionString at 010D6D74>
    >>> print getattr(object, method).__doc__
    Build a connection string from a dictionary of parameters.

        Returns string.

| 在 `info` 函数中，`object` 是要得到帮助的对象，作为一个参数传入。
| 在你遍历 `methodList` 时，`method` 是当前方法的名称。
| 通过 `getattr` 函数，你可以得到 `object` 模块中 `method` 函数的引用。
| 现在，很容易就可以打印出方法的 `doc string` 。

接下来令人困惑的是 `doc string` 周围 `str` 的使用。你可能记得，`str` 是一个内置函数，它可以强制将数据转化为字符串。但是一个 `doc string` 应该总是一个字符串，为什么还要费事地使用 `str` 函数呢？答案就是：不是每个函数都有 `doc string` ，如果没有，这个 `__doc__` 属性为 `None`。

### 例 4.23. 为什么对一个 `doc string` 使用 `str` ？

    >>> >>> def foo(): print 2
    >>> >>> foo()
    2
    >>> >>> foo.__doc__
    >>> foo.__doc__ == None
    True
    >>> str(foo.__doc__)
    'None'

| 你可以很容易的定义一个没有 `doc string` 的函数，这种情况下它的 `__doc__` 属性为 `None`。令人迷惑的是，如果你直接演算 `__doc__` 属性的值，Python IDE 什么都不会打印。这是有意义的 (前提是你考虑了这个结果的来由)，但是却没有什么用。
| 你可以直接通过 `__doc__` 属性和 `None` 的比较验证 `__doc__` 属性的值。
| `str` 函数可以接收值为 null 的参数，然后返回它的字符串表示，`'None'`。

在 SQL 中，你必须使用 `IS NULL` 代替 `= NULL` 进行 null 值比较。在 Python，你可以使用 `== None` 或者 `is None` 进行比较，但是 `is None` 更快。

现在你确保有了一个字符串，可以把这个字符串传给 `processFunc`，这个函数已经定义是一个既可以压缩空白也可以不压缩空白的函数。现在你看出来为什么使用 `str` 将 `None` 转化为一个字符串很重要了。`processFunc` 假设接收到一个字符串参数然后调用 `split` 方法，如果你传入 `None` ，将导致程序崩溃，因为 `None` 没有 `split` 方法。

再往回走一步，你再一次使用了字符串格式化来连接 `processFunc` 的返回值 和 `method` 的 `ljust` 方法的返回值。`ljust` 是一个你之前没有见过的新字符串方法。

### 例 4.24. `ljust` 方法介绍

    >>> s = 'buildConnectionString'
    >>> s.ljust(30)
    'buildConnectionString         '
    >>> s.ljust(20)
    'buildConnectionString'

| `ljust` 用空格填充字符串以符合指定的长度。`info` 函数使用它生成了两列输出并将所有在第二列的 `doc string` 纵向对齐。
| 如果指定的长度小于字符串的长度，`ljust` 将简单地返回未变化的字符串。它决不会截断字符串。

几乎已经完成了。有了 `ljust` 方法填充过的方法名称和来自调用 `processFunc` 方法得到的 `doc string` (可能压缩过)，你就可以将两者连接起来并得到单个字符串。因为对 `methodList` 进行了映射，最终你将获得一个字符串列表。利用 `"\n"` 的 `join` 函数，将这个列表连接为单个字符串，列表中每个元素独占一行，接着打印出结果。

### 例 4.25. 打印列表

    >>> li = ['a', 'b', 'c']
    >>> print "\n".join(li)
    a
    b
    c

| 在你处理列表时，这确实是一个有用的调试技巧。在 Python 中，你会十分频繁地操作列表。

上述就是最后一个令人困惑的地方了。但是现在你应该已经理解这段代码了。

        print "\n".join(["%s %s" %
                          (method.ljust(spacing),
                           processFunc(str(getattr(object, method).__doc__)))
                         for method in methodList])