使用tokenize
模块时,我发现了一些奇怪的行为
import tokenize, io, sys
from contextlib import closing
source=u"""
for i in range(10):
print "HELLO"
if i==5:
print "bingo"
"""
def parse():
with closing(io.StringIO(source)) as f:
for type, token, (srow, scol), (erow, ecol), line in tokenize.generate_tokens(f.readline):
print("%d,%d-%d,%d:\t%s\t%s" % (srow, scol, erow, ecol, tokenize.tok_name[type], repr(token)))
yield type, token, (srow, scol), (erow, ecol), line
for token in tokenize.untokenize(parse()):
sys.stdout.write(token)
控制台输出中缺少if
之前的INDENT。它发生在python2和3上。
这是一个已知的错误还是我以错误的方式使用该模块?
3,1-3,6: NAME u'print'
3,7-3,14: STRING u'"HELLO"'
3,14-3,15: NEWLINE u'\n'
4,1-4,3: NAME u'if'
4,4-4,5: NAME u'i'
4,5-4,7: OP u'=='
我使用标签进行缩进。当我用4个空格替换标签时,我得到了正确的结果
3,4-3,9: NAME u'print'
3,10-3,17: STRING u'"HELLO"'
3,17-3,18: NEWLINE u'\n'
4,4-4,6: NAME u'if'
4,7-4,8: NAME u'i'
4,8-4,10: OP u'=='
4,10-4,11: NUMBER u'5'
4,11-4,12: OP u':'
区别在于if
的起始列,使用制表符时为1,使用空格时为4。
它似乎是'untokenize'函数中的一个错误,似乎输出空格而不是制表符。
有人可以确认吗?
答案 0 :(得分:1)
一切都应该如此。列索引基于0。一个tab
是一个字符,因此在第1列中正确检测到if
。当您将此tab
更改为4 spaces
时,确实有4个字符,因此if
在第4栏中检测到。
从您的代码输出证明:
1,0-1,1: NL u'\n'
2,0-2,3: NAME u'for'
如您所见,第一行中的linefeed
和第二行中的for
都位于第0列。
您可能会感到困惑,因为行号是基于1的。
脚注:您应该使用空格进行缩进。这是一种确保在另一台开发人员的机器上一致显示缩进的惯例。可以调整显示的标签宽度,空格宽度只是一个字符。
修改强>
在OP的评论认为tokenize
和untokenize
存在问题后,我必须添加以下注释。
如official documentation says:
保证结果标记化以匹配输入,以便转换无损并确保往返。 保证仅适用于令牌类型和令牌字符串,因为令牌(列位置)之间的间距可能会发生变化。