On this page
tokenize —用于 Python 的 Tokenizer 源
源代码: Lib/tokenize.py
tokenize模块为 Python 源代码提供了词法扫描器,该词法扫描器以 Python 实现。该模块中的扫描仪也以令牌的形式返回 Comments,这对于实现“漂亮打印机”(包括用于屏幕显示的着色器)非常有用。
为了简化令牌流的处理,使用通用的OP令牌类型返回所有operator和delimiter令牌以及Ellipsis。可以pass检查tokenize.tokenize()返回的named tuple的exact_type
属性来确定确切的类型。
Tokenizing Input
主要入口点是generator:
tokenize.
tokenize
(* readline *)- tokenize()生成器需要一个参数* readline *,该参数必须是可调用的对象,该对象提供与文件对象的io.IOBase.readline()方法相同的接口。每次对函数的调用都应以字节为单位返回一行 Importing。
生成器生成具有以下成员的 5Tuples:令牌类型;令牌字符串; 2 元整数(srow, scol)
int,用于指定源中令牌开始的行和列;一个 2 整数(erow, ecol)
的整数,指定标记在源中结束的行和列;以及找到令牌的行。传递的行(最后一个 Tuples 项)是* physical *行。 5 个 Tuples 以named tuple的形式返回,其字段名称为type string start end line
。
返回的named tuple具有名为exact_type
的附加属性,其中包含OP令牌的确切运算符类型。对于所有其他令牌类型,exact_type
等于命名的 Tuplestype
字段。
在版本 3.1 中进行了更改:添加了对命名 Tuples 的支持。
在版本 3.3 中进行了更改:添加了对exact_type
的支持。
tokenize()根据 PEP 263pass查找 UTF-8 BOM 或编码 cookie 来确定文件的源编码。
tokenize.
generate_tokens
(* readline *)- 对读取 unicode 字符串而不是字节的源标记化。
像tokenize()一样,* readline 参数是可调用的,返回单行 Importing。但是,generate_tokens()期望 readline *返回一个 str 对象而不是字节。
结果是一个迭代器产生了名为 tuple 的 Tuples,就像tokenize()一样。它不会产生ENCODING令牌。
提供了另一个Function来逆转令牌化过程。这对于创建标记脚本脚本,修改标记流以及写回修改后脚本的工具很有用。
tokenize.
untokenize
(可迭代)- 将令牌转换回 Python 源代码。 * iterable *必须返回至少包含两个元素的序列:令牌类型和令牌字符串。任何其他序列元素都将被忽略。
重建的脚本作为单个字符串返回。保证结果可以令牌化回去以匹配 Importing,从而使转换无损并确保往返。由于令牌之间的间距(列位置)可能会更改,因此该保证仅适用于令牌类型和令牌字符串。
它返回使用ENCODING令牌编码的字节,这是tokenize()输出的第一个令牌序列。如果 Importing 中没有编码令牌,它将返回一个 str。
tokenize()需要检测它标记化的源文件的编码。它用于执行此操作的Function可用:
tokenize.
detect_encoding
(* readline *)- detect_encoding()函数用于检测解码 Python 源文件时应使用的编码。与tokenize()生成器相同,它需要一个参数 readline。
它将最多调用 readline 两次,并返回已使用的编码(作为字符串)和所有已读入的行的列表(未从字节解码)。
它根据 PEP 263中指定的 UTF-8 BOM 或编码 cookie 来检测编码。如果同时存在 BOM 和 cookie,但不同意,则会引发SyntaxError。请注意,如果找到 BOM,则将返回'utf-8-sig'
作为编码。
如果未指定编码,则将返回默认值'utf-8'
。
使用open()打开 Python 源文件:使用detect_encoding()检测文件编码。
tokenize.
open
(* filename *)- 使用detect_encoding()检测到的编码以只读模式打开文件。
3.2 版中的新Function。
- exception
tokenize.
TokenError
- 当文档字符串或表达式可能会分成几行时,在文件中的任何位置未完成时引发,例如:
"""Beginning of
docstring
or:
[1,
2,
3
请注意,未封闭的单引号字符串不会引起错误。它们被标记为ERRORTOKEN,随后是其内容的标记。
Command-Line Usage
版本 3.3 中的新Function。
tokenize模块可以从命令行作为脚本执行。它很简单:
python -m tokenize [-e] [filename.py]
接受以下选项:
-h
`,` `--help`
- 显示此帮助消息并退出
-e
`,` `--exact`
- 使用确切类型显示令牌名称
如果指定了filename.py
,其内容将标记为 stdout。否则,将在标准 Importing 上执行标记化。
Examples
将浮点 Literals 转换为 Decimal 对象的脚本重写器的示例:
from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
from io import BytesIO
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'))"
The format of the exponent is inherited from the platform C library.
Known cases are "e-007" (Windows) and "e-07" (not Windows). Since
we're only showing 12 digits, and the 13th isn't close to 5, the
rest of the output should be platform-independent.
>>> exec(s) #doctest: +ELLIPSIS
-3.21716034272e-0...7
Output from calculations with Decimal should be identical across all
platforms.
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = tokenize(BytesIO(s.encode('utf-8')).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).decode('utf-8')
从命令行进行标记化的示例。剧本:
def say_hello():
print("Hello, World!")
say_hello()
将被标记为以下输出,其中第一列是找到令牌的行/列坐标的范围,第二列是令牌的名称,最后一列是令牌的值(如果有)
$ python -m tokenize hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: OP '('
1,14-1,15: OP ')'
1,15-1,16: OP ':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ' '
2,4-2,9: NAME 'print'
2,9-2,10: OP '('
2,10-2,25: STRING '"Hello, World!"'
2,25-2,26: OP ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT ''
4,0-4,9: NAME 'say_hello'
4,9-4,10: OP '('
4,10-4,11: OP ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
可以使用-e选项显示确切的令牌类型名称:
$ python -m tokenize -e hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: LPAR '('
1,14-1,15: RPAR ')'
1,15-1,16: COLON ':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ' '
2,4-2,9: NAME 'print'
2,9-2,10: LPAR '('
2,10-2,25: STRING '"Hello, World!"'
2,25-2,26: RPAR ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT ''
4,0-4,9: NAME 'say_hello'
4,9-4,10: LPAR '('
4,10-4,11: RPAR ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
以编程方式标记文件的示例,使用generate_tokens()读取 unicode 字符串而不是字节:
import tokenize
with tokenize.open('hello.py') as f:
tokens = tokenize.generate_tokens(f.readline)
for token in tokens:
print(token)
或直接使用tokenize()读取字节:
import tokenize
with open('hello.py', 'rb') as f:
tokens = tokenize.tokenize(f.readline)
for token in tokens:
print(token)