我的目标是在python中找到循环语句的开头和结尾的行号。
示例场景
#A.py
Line1: a=0
Line2: while a<5:
Line3: print a
Line4: a=a+1
Desired output:
Start of a loop Line2
End of a loop Line4
当前解析器代码
#parser.py
with open(a) as f:
tree = ast.parse(f.read())
taskline=[]
for node in ast.walk(tree):
if isinstance(node, (ast.For)) or isinstance(node,(ast.While)):
print node.lineno-1 <-- This give line number on for the start of a loop
我想实现上述输出。我使用AST来解析给定的文件并确定循环的发生。使用AST解析,我能够找到循环开始的行号,但是尚未确定循环结束的行号。有什么办法可以解析整个循环语句并确定它的起始和结束行号吗?
答案 0 :(得分:4)
While
节点的语句在node.body
列表中。 while
循环的最后一行是列表的最后一行。我不知道你为什么要减去一个(除非你的文件a
有你想要假装的评论不存在):
$ cat a.py
a = 0
while a < 5:
print a
a += 1
for i in (1, 2, 3):
pass
$ cat ast_ex.py
import ast
with open('a.py') as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, (ast.For, ast.While)):
print 'node:', node, 'at line:', node.lineno
print 'body of loop ends at:', node.body[-1].lineno
$ python ast_ex.py
node: <_ast.While object at 0x8017a8e50> at line: 2
body of loop ends at: 4
node: <_ast.For object at 0x8017ac0d0> at line: 5
body of loop ends at: 6
循环中的第一行是body[0]
(如果循环中只有一个语句,则可能与body[-1]
相同。)
答案 1 :(得分:0)
它可以被复制,但您可以尝试遵循算法。
1. Count the number of white spaces before while. say it ident(you can use something like this len(a) - len(a.lstrip()) )
2. countinue reading the next line and counting the white spaces before the line say currIdent.
3. when ever currIdent = ident, then end of loop is line before it.
答案 2 :(得分:0)
我对ast
模块并不是很熟悉,但下面的代码在一些测试示例中对我有用。它返回一个2元组的列表,每个元素对应一个文件中的每个循环,其中每个元组看起来像(start_line, end_line)
。
def get_loop_boundaries(fname):
boundaries = []
with open(fname) as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, (ast.For)) or isinstance(node,(ast.While)):
loop_start = node.lineno
# body attribute is a list of nodes, one for each line in the loop
# the lineno of the last node will give us the ending line
loop_end = node.body[-1].lineno
# add 2-tuple of starting and ending lines for current loop to list
boundaries.append((loop_start, loop_end))
# return a list of starting and ending lines for all loops in fname file
return boundaries
我刚刚意识到函数的主要逻辑可以更简洁地编写为列表理解:
return [(node.lineno, node.body[-1].lineno) for node in ast.walk(tree) if isinstance(node, (ast.For, ast.While))]
答案 3 :(得分:0)
Torek's answer 非常好,我自己也尝试在我的程序中使用它,但还有另一种方法可以做到。 'ast' 类提供了一个名为 'end_lineno' 的功能,就像 lineno 一样。这可用于查找循环结束的 lineno。请参阅docs
import ast
with open('a.py') as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, (ast.For, ast.While)):
print 'node:', node, 'at line:', node.lineno
print 'body of loop ends at:', node.end_lineno