32.7. tokenize —用于 Python 的 Tokenizer 源

源代码: Lib/tokenize.py


tokenize模块为 Python 源代码提供了词法扫描器,该词法扫描器以 Python 实现。该模块中的扫描仪也以令牌的形式返回 Comments,这对于实现“漂亮打印机”(包括用于屏幕显示的着色器)非常有用。

为了简化令牌流的处理,使用通用的token.OP令牌类型返回所有OperatorsDelimiters令牌。可以pass检查从tokenize.generate_tokens()返回的 Tuples 的第二个字段(包含匹配的实际令牌字符串)来确定标识特定操作员令牌的字符序列,从而确定确切的类型。

主要入口点是generator

  • tokenize. generate_tokens(* readline *)
    • generate_tokens()生成器需要一个参数* readline ,该参数必须是可调用的对象,该对象提供与内置文件对象的readline()方法相同的接口(请参见File Objects)。每次对函数的调用都应以字符串形式返回一行 Importing。另外, readline *可以是可调用的对象,它pass提高StopIteration来表示完成。

生成器生成具有以下成员的 5Tuples:令牌类型;令牌字符串; 2 个 Tuples 的(srow, scol) int,用于指定源中令牌开始的行和列; 2 元整数(erow, ecol) int,用于指定令牌在源中结束的行和列;以及找到令牌的行。传递的行(最后一个 Tuples 项)是逻辑行;包括续行。

2.2 版中的新Function。

保留了较旧的入口点以实现向后兼容性:

  • tokenize. tokenize(* readline * [,* tokeneater *])
    • tokenize()函数接受两个参数:一个代表 Importing 流,另一个为tokenize()提供输出机制。

第一个参数* readline 必须是可调用对象,该对象提供与内置文件对象的readline()方法相同的接口(请参见File Objects)。每次对函数的调用都应以字符串形式返回一行 Importing。或者, readline *可以是可调用的对象,它pass提高StopIteration来表示 signal 完成。

在版本 2.5 中进行了更改:添加了StopIteration支持。

第二个参数* tokeneater *也必须是可调用对象。每个令牌都调用一次,带有五个参数,分别对应于generate_tokens()生成的 Tuples。

token模块中的所有常量也都从tokenize中导出,另外两个可能由tokenize()传递给* tokeneater *函数的令牌类型值也是如此:

  • tokenize. COMMENT

    • 用于指示 Comment 的令牌值。
  • tokenize. NL

    • 用于指示非终止换行符的令牌值。 NEWLINE 令牌指示 Python 代码的逻辑行的结尾;当逻辑代码行在多个物理行上连续时,会生成 NL 令牌。

提供了另一个Function来逆转令牌化过程。这对于创建标记脚本脚本,修改标记流以及写回修改后脚本的工具很有用。

  • tokenize. untokenize(可迭代)
    • 将令牌转换回 Python 源代码。 * iterable *必须返回至少包含两个元素的序列:令牌类型和令牌字符串。任何其他序列元素都将被忽略。

重建的脚本作为单个字符串返回。保证结果可以令牌化回去以匹配 Importing,从而使转换无损并确保往返。由于令牌之间的间距(列位置)可能会更改,因此该保证仅适用于令牌类型和令牌字符串。

2.5 版的新Function。

  • exception tokenize. TokenError
    • 当文档字符串或表达式可能会分成几行时,在文件中的任何位置未完成时引发,例如:
"""Beginning of
docstring

or:

[1,
 2,
 3

请注意,未封闭的单引号字符串不会引起错误。它们被标记为ERRORTOKEN,随后是其内容的标记。

将浮点 Literals 转换为 Decimal 对象的脚本重写器示例:

def decistmt(s):
    """Substitute Decimals for floats in a string of statements.

    >>> from decimal import Decimal
    >>> s = 'print +21.3e-5*-.1234/81.7'
    >>> decistmt(s)
    "print +Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7')"

    >>> exec(s)
    -3.21716034272e-007
    >>> exec(decistmt(s))
    -3.217160342717258261933904529E-7

    """
    result = []
    g = generate_tokens(StringIO(s).readline)   # tokenize the string
    for toknum, tokval, _, _, _  in g:
        if toknum == NUMBER and '.' in tokval:  # replace NUMBER tokens
            result.extend([
                (NAME, 'Decimal'),
                (OP, '('),
                (STRING, repr(tokval)),
                (OP, ')')
            ])
        else:
            result.append((toknum, tokval))
    return untokenize(result)