tokenize --- Python ソース用のトークナイザー¶
ソースコード: Lib/tokenize.py
The tokenize module provides a lexical scanner for Python source code,
implemented in Python. The scanner in this module returns comments as tokens
as well, making it useful for implementing "pretty-printers", including
colorizers for on-screen displays.
To simplify token stream handling, all operator and
delimiter tokens and Ellipsis are returned using
the generic OP token type.
The TokenInfo.exact_type property gives the exact token type.
警告
このモジュールの関数は、構文的に有効な Python コード (ast.parse() で解析しても例外を送出しないコード) を解析するためだけに設計されています。
不正な Python コードを与えた場合の動作は 未定義 であり、いつでも変わる可能性があります。
Tokenizing Input¶
第一のエントリポイントは ジェネレータ です:
- tokenize.tokenize(readline)¶
tokenize()ジェネレータは一つの引数 readline を必要とします。この引数は呼び出し可能オブジェクトで、ファイルオブジェクトのio.IOBase.readline()メソッドと同じインタフェースを提供している必要があります。この関数は呼び出しのたびに入力の一行を bytes で返さなければなりません。The generator produces
TokenInfoobjects.バージョン 3.1 で変更: Changed to yield
TokenInfoobjects instead of plain tuples.tokenize()は PEP 263 にしたがって、ソースのエンコーディングを UTF-8 BOM か encoding cookie を見つけて決定します。
- tokenize.generate_tokens(readline)¶
バイト列ではなく Unicode 文字列を読み取り、ソースをトークン化します。
tokenize()と同じく、readline 引数は入力を 1 行返す呼び出し可能オブジェクトです。 ただしgenerate_tokens()では、readline は bytes ではなく str オブジェクトを返す必要があります。The result is an iterator yielding
TokenInfoobjects, exactly liketokenize(). It does not yield anENCODINGtoken.
- class tokenize.TokenInfo(type, string, start, end, line)¶
A named tuple describing a token. It has five fields and an additional
exact_typeproperty.Added in version 3.1.
- type¶
An integer identifying the token type, as defined by the constants in
token, such asNAMEandSTRING. Operators and delimiters have typeOP; useexact_typefor their specific token type.
- string¶
The token text as a
str. ForSTRINGtokens, this includes the quotes, any prefix, and escape sequences, without evaluating them.For an
ENCODINGtoken, this is the encoding name. Tokens inserted without corresponding source text can have an empty string. InFSTRING_MIDDLEandTSTRING_MIDDLEtokens, doubled braces are replaced by single braces.
- start¶
A 2-tuple
(srow, scol)of ints specifying the inclusive start position of the token in the source. Rows are numbered from 1 and columns from 0. Columns count Unicode code points; a tab counts as one column, without expanding it to a tab stop.For an
ENCODINGtoken, this is(0, 0).
- end¶
A 2-tuple
(erow, ecol)of ints specifying the exclusive end position of the token. Rows are numbered from 1 and columns from 0. For a token spanning multiple lines, erow is the final row and ecol is the column on that row.For example, the name
spamat the beginning of the first line hasstartequal to(1, 0)andendequal to(1, 4).For an
ENCODINGtoken, this is(0, 0). ANEWLINEorNLtoken inserted at the end of input without a final newline can have an end column one beyond the source text.
token モジュールのすべての定数は、tokenize からも公開されています。
もう一つの関数がトークン化プロセスを逆転するために提供されています。これは、スクリプトを字句解析し、トークンのストリームに変更を加え、変更されたスクリプトを書き戻すようなツールを作成する際に便利です。
- tokenize.untokenize(iterable)¶
トークンの列を Python ソースコードに変換します。 iterable は少なくとも二つの要素、トークンタイプおよびトークン文字列、からなるシーケンスを返さなければいけません。 その他のシーケンスの要素は無視されます。
結果を再びトークン化すると入力と一致することが保証されるため、情報を失わずに往復変換できます。 ただし保証されるのはトークン型とトークン文字列だけで、トークン間の空白 (列位置) は変わることがあります。
tokenize()が最初に出力するトークンであるENCODINGを使ってエンコードしたバイト列を返します。 入力にエンコーディングのトークンがなければ、代わりに str を返します。
tokenize() はトークナイズしようとしているソースファイルのエンコーディングを検出する必要があります。これを行うために使っている関数が公開されています:
- tokenize.detect_encoding(readline)¶
detect_encoding()関数は Python のソースファイルをデコードするのに使うエンコーディングを検出するために使われます。tokenize()ジェネレータと同じ readline を引数として取ります。readlineを最大 2 回呼び出し、使うエンコーディング (文字列) と、読み込んだ行のリスト (バイト列からデコードしないまま) を返します。UTF-8 BOM か PEP 263 で定義されている encoding cookie からエンコーディングを検出します。BOMと cookie の両方が存在し、一致していない場合、
SyntaxErrorが送出されます。 BOM が見つかった場合はエンコーディングとして'utf-8-sig'が返されます。エンコーディングが指定されていない場合、デフォルトの
'utf-8'が返されます。Python のソースファイルを開くには
open()を使ってください。これはdetect_encoding()を利用してファイルエンコーディングを検出します。
- tokenize.open(filename)¶
detect_encoding()を使って検出したエンコーディングを利用して、ファイルを読み出し専用モードで開きます。Added in version 3.2.
- exception tokenize.TokenError¶
docstring や複数行にわたることが許される式がファイル内のどこかで終わっていない場合に送出されます。例えば:
"""docstring の 始まり
もしくは:
[1, 2, 3
Command-Line Usage¶
Added in version 3.3.
tokenize モジュールは、コマンドラインからスクリプトとして実行できます。
次のようにするだけです:
python -m tokenize [-e] [filename.py]
以下のオプションが使用できます:
- -h, --help¶
このヘルプメッセージを出力して終了します
- -e, --exact¶
exact type を使ってトークン名を表示します
filename.py が指定された場合、その内容がトークナイズされ stdout に出力されます。指定されなかった場合は stdin からトークナイズします。
使用例¶
スクリプト書き換えの例で、浮動小数点数リテラルを 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()
will be tokenized to the following output where the first column is the range of the line/column coordinates where the token is found, the second column is the name of the token, and the final column is the value of the token (if any)
$ 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 ''
トークンの exact_type 名は -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 ''
バイト列ではなく Unicode 文字列を読み取り、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)