Skip to main content
 首页 » 编程设计

python之如何在模块中以文本方式查找导入的名称

2025年05月04日17del

我写了一个方法叫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 行中的整数给出了模块名称前的 . 的编号。