我目前正试图在Python文件中找到所有ast.Import
和ast.ImportFrom
节点。但是,在多行import语句中,如
from foo import (
bar,
baz,
coo
)
每个子模块(bar
,baz
和coo
)所提到的行号都在提到它们的行上,而不是原来的from foo import
行。我怎样才能得到import语句开始的那一行(对于单行导入,它是一样的)。
或者,是否有一种方法可以迭代地获得一个作用域中的所有导入(遍历脚本中的所有作用域)?
更新:显然,ast.walk
不像我想的那样为每行返回一个节点。这实际上是因为我为每个node.names
做了一个不同的元组。将其修改为只返回名字(并使用node.lineno)效果很好。不过@rici的回答还是不错的,所以我就不提了。
您可以只使用ast.ImportFrom
节点的lineno
属性,这是语句开始的行号。(还有一个end_lineno
属性,在这种情况下可能不太有用。)
下面是一个小例子:
import ast
sample = '''
# This is line 1
#
# This is line 3
#
# The next line is line 6
from foo import (
bar,
baz,
coo
)
import pkg.mod, other_mod
'''.strip()
class myWalker(ast.NodeVisitor):
def visit_Import(self, node):
print(f"""Line {node.lineno} imports modules {
', '.join(alias.name for alias in node.names)
}""")
def visit_ImportFrom(self, node):
print(f"""Line {node.lineno} imports from module {node.module} the names {
', '.join(alias.name for alias in node.names)
}""")
myWalker().visit(ast.parse(sample, filename='<test>', mode='exec'))
输出:
Line 6 imports from module foo the names bar, baz, coo
Line 11 imports modules pkg.mod, other_mod
要按作用域获取导入名称,我认为您必须遍历语法树,注意函数定义。(其他作用域,如lambda和推导式,在这里不重要,因为它们只允许表达式,不允许语句。但是,如果您想做得正确,还需要跟踪声明为global
或nonlocal
的名称,因为函数可以使用其中一种声明将导入的名称注入到不同的作用域。