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. 动态获取 文档字符串

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

    Returns string.
1 info 函数中,object 是您要获取帮助的对象,作为参数传入。
2 当您遍历 methodList 时,method 是当前方法的名称。
3 使用 getattr 函数,您将获得对 object 模块中 method 函数的引用。
4 现在,打印方法的实际 文档字符串 就很容易了。

下一个难题是 文档字符串 周围使用 str。您可能还记得,str 是一个内置函数,用于将数据 强制转换为字符串。但 文档字符串 始终是一个字符串,为什么要使用 str 函数呢?答案是并非每个函数都有 文档字符串,如果没有,则其 __doc__ 属性为 None

示例 4.23. 为什么要对 文档字符串 使用 str

>>> >>> def foo(): print 2
>>> >>> foo()
2
>>> >>> foo.__doc__     1
>>> foo.__doc__ == None 2
True
>>> str(foo.__doc__)    3
'None'
1 您可以轻松定义一个没有 文档字符串 的函数,因此其 __doc__ 属性为 None。令人困惑的是,如果您直接评估 __doc__ 属性,Python IDE 根本不会打印任何内容,如果您仔细想想,这是有道理的,但仍然没有帮助。
2 您可以通过直接比较来验证 __doc__ 属性的值实际上是 None
3 str 函数接受空值并返回其字符串表示形式,即 'None'
Note
SQL 中,您必须使用 IS NULL 而不是 = NULL 来比较空值。在 Python 中,您可以使用 == Noneis None,但 is None 更快。

现在您已经确定拥有一个字符串,您可以将该字符串传递给 processFunc,您已经将其 定义 为折叠或不折叠空格的函数。现在您明白为什么使用 strNone 值转换为字符串表示形式很重要。 processFunc 假定一个字符串参数并调用其 split 方法,如果您传递给它 None,它将会崩溃,因为 None 没有 split 方法。

再往回看,您会发现您再次使用字符串格式化将 processFunc 的返回值与 methodljust 方法的返回值连接起来。这是一个您以前从未见过的新的字符串方法。

示例 4.24. 介绍 ljust

>>> s = 'buildConnectionString'
>>> s.ljust(30) 1
'buildConnectionString         '
>>> s.ljust(20) 2
'buildConnectionString'
1 ljust 使用空格将字符串填充到给定的长度。这就是 info 函数用来生成两列输出并在第二列中对齐所有 文档字符串 的方法。
2 如果给定的长度小于字符串的长度,ljust 将只返回未更改的字符串。它从不截断字符串。

您快完成了。给定来自 ljust 方法的填充方法名称和来自对 processFunc 的调用的(可能已折叠的)文档字符串,您将两者连接起来并获得一个字符串。由于您正在映射 methodList,因此您最终会得到一个字符串列表。使用字符串 "\n"join 方法,您可以将此列表连接成一个字符串,列表中的每个元素都在单独的行上,并打印结果。

示例 4.25. 打印列表

>>> li = ['a', 'b', 'c']
>>> print "\n".join(li) 1
a
b
c
1 当您使用列表时,这也是一个有用的调试技巧。在 Python 中,您始终在使用列表。

这就是最后一个难题。您现在应该理解这段代码了。

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