32.7. tokenize — Python 源代码的 Tokenizer — Python 文档
32.7. 标记化 — 用于 Python 源代码的分词器
源代码: :source:`Lib/tokenize.py`
tokenize 模块为 Python 源代码提供了一个词法扫描器,用 Python 实现。 此模块中的扫描仪也将注释作为标记返回,这使其可用于实现“漂亮的打印机”,包括用于屏幕显示的着色器。
为了简化令牌流处理,使用通用 token.OP 令牌类型返回所有 Operators 和 Delimiters 令牌。 确切的类型可以通过检查从 tokenize.generate_tokens() 返回的元组的第二个字段(包含匹配的实际令牌字符串)中的字符序列来确定,该字符序列标识特定的操作符令牌。
主要入口点是 生成器 :
- tokenize.generate_tokens(readline)
generate_tokens() 生成器需要一个参数,readline,它必须是一个可调用对象,提供与内置的 readline() 方法相同的接口文件对象(请参阅 文件对象 部分)。 对函数的每次调用都应以字符串形式返回一行输入。 或者,readline 可以是一个可调用对象,它通过提高
StopIteration
来表示完成。生成器生成具有以下成员的 5 元组:令牌类型; 令牌字符串; 一个 2 元组
(srow, scol)
整数,指定标记在源中开始的行和列; 一个 2 元组(erow, ecol)
整数,指定标记在源中结束的行和列; 以及找到令牌的行。 传递的行(最后一个元组项)是 logical 行; 包括连续线。2.2 版中的新功能。
为了向后兼容,保留了一个较旧的入口点:
- tokenize.tokenize(readline[, tokeneater])
tokenize() 函数接受两个参数:一个代表输入流,一个为 tokenize() 提供输出机制。
第一个参数 readline 必须是一个可调用对象,它提供与内置文件对象的 readline() 方法相同的接口(参见 File Objects 部分])。 对函数的每次调用都应以字符串形式返回一行输入。 或者,readline 可以是一个可调用对象,它通过提高
StopIteration
来表示完成。2.5 版变更: 添加
StopIteration
支持。第二个参数 tokeneater 也必须是一个可调用对象。 它为每个令牌调用一次,有五个参数,对应于 generate_tokens() 生成的元组。
token 模块中的所有常量也从 tokenize 导出,还有两个额外的令牌类型值可能会通过 tokenize 传递给 tokeneater 函数():
- tokenize.COMMENT
- 用于指示评论的令牌值。
- tokenize.NL
- 用于指示非终止换行符的令牌值。 NEWLINE 标记表示 Python 代码逻辑行的结束; 当逻辑代码行在多个物理行上连续时生成 NL 令牌。
提供了另一个功能来反转标记化过程。 这对于创建标记脚本、修改令牌流和写回修改后的脚本的工具很有用。
- tokenize.untokenize(iterable)
将令牌转换回 Python 源代码。 iterable 必须返回包含至少两个元素的序列,标记类型和标记字符串。 任何附加的序列元素都将被忽略。
重建的脚本作为单个字符串返回。 结果保证标记回以匹配输入,以便转换是无损的并确保往返。 该保证仅适用于令牌类型和令牌字符串,因为令牌之间的间距(列位置)可能会发生变化。
2.5 版中的新功能。
- exception tokenize.TokenError
当文件中的任何地方都没有完成可能被分成几行的文档字符串或表达式时引发,例如:
"""Beginning of docstring
or:
[1, 2, 3
Note that unclosed single-quoted strings do not cause an error to be raised. They are tokenized as ERRORTOKEN
, followed by the tokenization of their contents.
Example of a script re-writer that transforms float literals into Decimal objects:
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)