这些只是可能的解决方案,因为我不太喜欢静态分析 。
与tokenize
:
我最近在弄乱标记化python代码的过程,我相信当添加足够的逻辑时,它具有执行此类检查所需的所有信息。对于给定的列表,使用生成的令牌
python -m tokenizelist1.py如下:
python -m tokenize list1.py1,0-1,4: NAME 'test'1,5-1,6: OP '='1,7-1,8: OP '['1,8-1,9: NL 'n'2,1-2,8: STRING '"item1"'2,8-2,9: NL 'n'3,1-3,8: STRING '"item2"'3,8-3,9: NL 'n'4,0-4,1: OP ']'4,1-4,2: newline 'n'5,0-5,0: ENDMARKER ''
当然,这是“ 有问题 ”的情况,其中内容将被连接在一起。在
,存在a的情况下,输出会略有变化以反映这一点(我仅为列表主体添加了标记):
1,7-1,8: OP '['1,8-1,9: NL 'n'2,1-2,8: STRING '"item1"'2,8-2,9: OP ','2,9-2,10: NL 'n'3,1-3,8: STRING '"item2"'3,8-3,9: NL 'n'4,0-4,1: OP ']'
现在,我们有了额外的
OP ','令牌,表示第二个元素的存在,以逗号分隔。
有了这些信息,我们可以
generate_tokens在
tokenize模块中使用真正方便的方法。方法
tokenize.generate_tokens(),
tokenize.tokenize()在
Py3具有一个参数
readline,在类文件对象的方法,其基本上返回下一行像对象(即文件相关答案)。它返回一个共有5个元素的命名元组,其中包含有关令牌类型,令牌字符串以及行号和行中位置的信息。
使用此信息,理论上可以遍历文件,并且在
OP ','列表初始化内不存在an时(可以通过检查标记来检测其开始
NAME,
OP '='并且
OP'['在相同的行号上存在),可以在该文件所在的行上发出警告被检测到。
这种方法的好处是概括起来很简单。为了适应所有发生字符串文字串联的情况(即在’grouping’运算符内部
(), {},[]),请检查令牌是否为type =51(或Python
3为53)或
(, [,{同一行中是否存在任何值(这些值比较粗糙) ,最重要的建议是atm)。现在, 我不太确定其他人如何解决这类问题, 但 似乎您可以研究一下
。所有必需的信息都由提供
tokenize,检测到它的逻辑是唯一缺少的东西。
实施注意: 这些值(例如for
type)在版本之间确实有所不同,并且可能会发生变化,因此应该注意这一点。但是,可以通过仅对令牌使用常量来利用这一点。
与parser
和ast
:
另一个可能更乏味的解决方案可能涉及
parser和
ast模块。字符串的连接实际上是在抽象语法树的创建过程中执行的,因此您可以在那儿进行检测。
我真的不希望转储的方法全力输出
parser,并
ast说我要提,但是,只是为了确保我们在同一页上,我将使用以下列表初始化语句:
l_init = """test = [ "item1" "item2", "item3"]"""
为了获得生成的解析树,请使用
p =parser.suite(l_init)。完成此操作后,您可以使用对其进行查看
p.tolist()(输出太大而无法添加)。你注意到那是什么
会有三个不同的三项
str目标
item1,
item2,
item3。
另一方面,使用AST创建
node =ast.parse(l_init)并查看AST时,
只有两个条目 :一个用于级联s
,一个用于另一个条目。
ast.dump(node)
__
str``item1item2``item3
因此,这是另一种可行的方法,但是,正如我之前提到的那样,它更繁琐。我不确定线路信息是否可用,您是否处理两个不同的模块。如果您想在编译器链中使用更高级别的内部对象,请回想一下。
收评
:作为一个闭注的
tokenize做法似乎是在这种情况下,最合理的一个。相反,似乎
pylint实际上可以与
astroidpython库一起使用,该库简化了python代码的抽象语法树的分析。因此,理想情况下应该查看它以及如何在pylint中使用它。
注意 : 当然 ,我可能对它进行了过多的分析,并且你们建议一个更简单的“检查空白或换行符”解决方案即可。:-)



