Ast парсинг ast.Expr типов

Есть кое-что, чего я не понимаю в смещении белья, которое вычисляется модулем ast. Обычно, когда я получаю белье некоторого аст-объекта, он дает мне первую строку, с которой встречается объект.

Например, в приведенном ниже случае, Линия foo

st='def foo():\n    print "hello"'
import ast
print ast.parse(st).body[0].lineno 
print ast.parse(st).body[0].body[0].lineno

вернет 1 для функции foo и вернет 2 для распечатки Привет, мир

Однако, если я анализирую многострочную строку документации (ast.Expr), предоставленное бельё является последней строкой.

st='def foo():\n    """\n    Test\n    """'   
import ast
print ast.parse(st).body[0].lineno 
print ast.parse(st).body[0].body[0].lineno

Результатом по-прежнему будет строка 1 для функции, но это будет строка 4 для строки документации. Я ожидал бы, что это будет на линии 2, так как именно тогда начинается строка документации.

Я предполагаю, что я спрашиваю, есть ли способ всегда получить первое белье из всех аст-объектов, включая ast.Expr .

1 ответ

Исходные местоположения AST оставляют желать лучшего, но многое из этого доступно в библиотеке ASTTokens, которая снабжает узлы AST более полезной информацией о местоположении. В вашем примере:

import asttokens
st='def foo():\n    """\n    Test\n    """'
atok = asttokens.ASTTokens(st, parse=True)

print atok.tree.body[0].first_token.start[0]
print atok.tree.body[0].body[0].first_token.start[0]

Печать 1 и 2 по желанию. Возможно, более интересно,

print atok.get_text_range(atok.tree.body[0])
print atok.get_text_range(atok.tree.body[0].body[0])

Печатает диапазоны исходного текста, соответствующие узлам: (0,35) и (15,35) в этом случае.

Другие вопросы по тегам