2013-07-30 3 views
2

Моя цель - найти номера строк начала и конца инструкции цикла в python.Как разобрать начало и конец операторов цикла в 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 для разбора данного файла и определения появления циклов. При анализе АСТ я могу найти номер строки для начала цикла, но номер строки для окончания цикла еще не определен. Есть ли способ, которым я мог бы разобрать весь оператор цикла и определить его начальный и конечный номер строки?

ответ

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], если в цикле есть только один оператор).

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. 
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))] 
+1

[torek's answer] (http://stackoverflow.com/a/17945479/111635) пояснил некоторые вещи, касающиеся модуля 'ast' для меня, поэтому я улучшил свою функцию. –

Смежные вопросы