我写了一个方法叫buildRegex
给定一个名称(类型为 str
),返回一个 regex
找到 from ... import ... name
的对象Python
中的声明模块。
例如,这是 buildRegex
的预期行为:
>>> regObj = buildRegex('foo')
>>> regObj.search('from a import fool') is None
True
>>> regObj.search('from a import foo') is not None
True
>>> regObj.search('from a.b.c import foo as food') is None
True
>>> regObj.search('from a.b.c import fool, bar as foo') is not None
True
到目前为止,我所拥有的适用于上述所有示例(以及更多):
def buildRegex(name):
singleImportedName = r'(\b{0}\b(?!\s+as\s+))'.format(name)
importStatement = r'from\s+(\w+(\.\w+)*)\s+import\s+([^#\n]*)(?={0})'.format(singleImportedName )
return re.compile(importStatement)
buildRegex
假设搜索到的模块没有 SyntaxError
这没关系。
我的问题是,在查找导入名称时 foo
,我还需要知道它是否是其他名称的别名。 IE。如果一个模块有语句:
from a.b.c import bar as foo
我想知道什么foo
是别名,在这种情况下,这将是 bar
.目前,由于 asserted lookaheads
在正则表达式中,这是不可能的。所以,最后我的问题是:
我如何重构正则表达式以使此信息不丢失,即,如果给定名称是别名,则其别名的名称位于 regex
之一。的 groups ?
最佳答案
我建议不要编写复杂的正则表达式来解析导入,而是实际使用 ast.parse
将源代码解析为抽象语法树并从那里找到名称,如ast.parse
保证正确解析 Python。像这样的东西:
import ast
class ImportFinder(ast.NodeVisitor):
def __init__(self):
self.imports = []
def visit_Import(self, node):
names = []
for i in node.names:
names.append((i.name, i.asname))
self.imports.append(['import', names])
def visit_ImportFrom(self, node):
module = node.module
level = node.level # how many dots
names = []
for i in node.names:
names.append((i.name, i.asname))
self.imports.append(('from', level, module, names))
def parse_imports(source):
tree = ast.parse(source)
finder = ImportFinder()
finder.visit(tree)
return finder.imports
示例用法:
import pprint
pprint.pprint(parse_imports('''
from foo import bar, baz, frob
from .. import bar as spam, baz as ham, frob
import bar.baz
import bar.foo as baf
'''))
打印出来:
[('from', 0, 'foo', [('bar', None), ('baz', None), ('frob', None)]),
('from', 2, None, [('bar', 'spam'), ('baz', 'ham'), ('frob', None)]),
['import', [('bar.baz', None)]],
['import', [('bar.foo', 'baf')]]]
from
行中的整数给出了模块名称前的 .
的编号。
关于python - 如何在模块中以文本方式查找导入的名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30037326/