tokenize
——python源的tokenizer¶
源代码: Lib/tokenize.py
这个 tokenize
模块为用Python实现的Python源代码提供词法扫描器。此模块中的扫描仪还将注释作为标记返回,这使得它对于实现“漂亮的打印机”非常有用,包括用于屏幕显示的着色器。
为了简化令牌流处理,所有 operator 和 delimiter 令牌和 Ellipsis
使用泛型返回 OP
令牌类型。通过检查 exact_type
属性上 named tuple 从回来 tokenize.tokenize()
.
标记化输入¶
主要入口点是 generator :
- tokenize.tokenize(readline)¶
这个
tokenize()
生成器需要一个参数, readline ,它必须是提供与io.IOBase.readline()
文件对象的方法。对函数的每次调用都应返回一行字节输入。生成器使用以下成员生成5个元组:标记类型;标记字符串;2个元组
(srow, scol)
指定标记在源中开始的行和列的整数;2元组(erow, ecol)
指定标记在源中结束的行和列;以及找到标记的行。传递的行(最后一个元组项)是 身体的 行。5元组作为 named tuple 字段名:type string start end line
.归还的人 named tuple 具有名为的附加属性
exact_type
它包含OP
令牌。对于所有其他令牌类型exact_type
等于命名的元组type
字段。在 3.1 版更改: 添加了对命名元组的支持。
在 3.3 版更改: 为添加了支持
exact_type
.tokenize()
根据 PEP 263 .
- tokenize.generate_tokens(readline)¶
将读取Unicode字符串而不是字节的源标记化。
类似于
tokenize()
, the readline 参数是可调用的,返回一行输入。然而,generate_tokens()
预期 readline 返回str对象而不是字节。结果是一个迭代器产生了命名的元组,与
tokenize()
. 它不产生ENCODING
令牌。
所有常量来自 token
模块也从导出 tokenize
.
提供了另一个功能来逆转标记化技术过程。这对于创建标记化脚本、修改标记流和写回修改过的脚本的工具很有用。
- tokenize.untokenize(iterable)¶
将标记转换回python源代码。这个 可迭代的 必须返回至少包含两个元素的序列,标记类型和标记字符串。忽略任何其他序列元素。
重建的脚本作为单个字符串返回。结果保证了标记化回匹配输入,从而保证了转换的无损性和往返性。保证仅适用于令牌类型和令牌字符串,因为令牌之间的间距(列位置)可能会更改。
它返回字节,使用
ENCODING
令牌,它是由tokenize()
. 如果输入中没有编码标记,则返回str。
tokenize()
需要检测它标记的源文件的编码。它用于执行此操作的功能可用:
- tokenize.detect_encoding(readline)¶
这个
detect_encoding()
函数用于检测用于解码Python源文件的编码。它需要一个参数readline,与tokenize()
生成器。它最多调用readline两次,并返回所使用的编码(作为字符串)和它已读取的任何行(不是从字节解码)的列表。
它根据中指定的UTF-8 BOM或编码cookie检测编码。 PEP 263 . 如果同时存在一个BOM和一个cookie,但不同意,
SyntaxError
将被引发。请注意,如果找到了物料清单,'utf-8-sig'
将作为编码返回。如果未指定编码,则默认为
'utf-8'
将被退回。使用
open()
打开python源文件:它使用detect_encoding()
检测文件编码。
- tokenize.open(filename)¶
使用检测到的编码以只读模式打开文件
detect_encoding()
.3.2 新版功能.
- exception tokenize.TokenError¶
在文件中的任何位置未完成可拆分为多行的docstring或表达式时引发,例如::
"""Beginning of docstring
或:
[1, 2, 3
请注意,未闭合的单引号字符串不会导致引发错误。它们被标记为 ERRORTOKEN
然后对其内容进行标记化技术。
命令行用法¶
3.3 新版功能.
这个 tokenize
模块可以作为脚本从命令行执行。它简单如下:
python -m tokenize [-e] [filename.py]
接受以下选项:
- -h, --help¶
显示此帮助消息并退出
- -e, --exact¶
使用确切类型显示令牌名称
如果 filename.py
它的内容被标记为stdout。否则,在stdin上执行标记化技术。
实例¶
将浮点文字转换为十进制对象的脚本重写器示例:
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()
::
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)