32.7. tokenize
- Python源代码¶
源代码: Lib / tokenize.py
tokenize
模块为Python源代码提供了一个词法扫描器,在Python中实现。该模块中的扫描器也返回作为标记的注释,使得它对于实现“漂亮打印机”很有用,包括用于屏幕显示的着色器。
为了简化令牌流处理,使用通用的token.OP
令牌类型返回所有Operators和Delimiters令牌。确切类型可以通过检查tokenize.tokenize()
返回的named tuple上的exact_type
属性来确定。
32.7.1. Tokenizing Input¶
主要入口点是generator:
-
tokenize.
tokenize
(readline)¶ tokenize()
生成器需要一个参数readline,它必须是一个可调用对象,它提供与io.IOBase.readline()
每个函数的调用都应该返回一行输入作为字节。The generator produces 5-tuples with these members: the token type; the token string; a 2-tuple
(srow, scol)
of ints specifying the row and column where the token begins in the source; a 2-tuple(erow, ecol)
of ints specifying the row and column where the token ends in the source; and the line on which the token was found. 传递的行(最后一个元组项)是逻辑行;连续线。5元组作为named tuple返回,其字段名称为:type string start end 行
。返回的named tuple有一个名为
exact_type
的附加属性,其中包含token.OP
令牌的确切操作符号类型。对于所有其他令牌类型,exact_type
等于命名的元组type
字段。在版本3.1中已更改:添加了对命名元组的支持。
在版本3.3中已更改:添加对
exact_type
的支持。tokenize()
根据 PEP 263,通过查找UTF-8 BOM或编码Cookie来确定文件的源编码。
token
模块中的所有常量也从tokenize
导出,以及三个附加的令牌类型值:
-
tokenize.
COMMENT
¶ 用于表示注释的令牌值。
-
tokenize.
NL
¶ 用于表示非终止换行符的令牌值。NEWLINE标记表示Python代码的逻辑行的结束;当逻辑代码行在多个物理线路上继续时,生成NL令牌。
-
tokenize.
ENCODING
¶ 表示用于将源字节解码为文本的编码的令牌值。
tokenize()
返回的第一个令牌将始终是ENCODING令牌。
提供了另一个功能来反转令牌化过程。这对创建标记脚本,修改令牌流和回写修改的脚本的工具很有用。
-
tokenize.
untokenize
(iterable)¶ 将令牌转换回Python源代码。iterable必须返回具有至少两个元素的序列,即令牌类型和令牌字符串。任何其他序列元素都将被忽略。
重构的脚本作为单个字符串返回。结果保证将令牌化返回以匹配输入,使得转换是无损的并且确保往返行程。保证仅适用于令牌类型和令牌字符串,因为令牌之间的间隔(列位置)可能改变。
它返回使用ENCODING令牌编码的字节,ENCODING令牌是
tokenize()
输出的第一个令牌序列。
tokenize()
需要检测其标记化的源文件的编码。它使用的功能可用:
-
tokenize.
detect_encoding
(readline)¶ detect_encoding()
函数用于检测应用于解码Python源文件的编码。它需要一个参数readline,其方式与tokenize()
生成器相同。它将调用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中的新功能。
- exception
tokenize.
TokenError
¶ 在可能拆分为多行的docstring或表达式未在文件中的任何位置完成时触发,例如:
"""Beginning of docstring
要么:
[1, 2, 3
请注意,未闭合的单引号字符串不会引起错误。它们被标记为ERRORTOKEN
,随后是其内容的标记化。
32.7.2. Command-Line Usage¶
版本3.3中的新功能。
tokenize
模块可以作为脚本从命令行执行。它很简单:
python -m tokenize [-e] [filename.py]
接受以下选项:
-
-h
,
--help
¶
显示此帮助消息并退出
-
-e
,
--exact
¶
使用确切类型显示令牌名称
如果指定filename.py
,它的内容被标记为stdout。否则,对stdin执行标记化。
32.7.3. Examples¶
将浮点字面值转换为十进制对象的脚本重写器示例:
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 ''