繁体   English   中英

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

[英]How to textually find an imported name in a module

我编写了一个名为buildRegex的方法,给定名称(类型为str ),它返回一个regex对象,该对象from ... import ... name Python模块中的from ... import ... name语句中查找。

例如,这是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 ,我还需要知道它是否是其他名称的别名。 即模块是否具有以下语句:

from a.b.c import bar as foo

我想知道foo是什么别名,在这种情况下,应该是bar 当前,由于在正则表达式中asserted lookaheads ,这是不可能的。 所以,最后是我的问题:如何重构正则表达式,以使该信息不会丢失,即,如果给定名称是别名,那么其别名就是该regex组之一

我建议您不要编写复杂的正则表达式来解析导入,而是实际使用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行上的整数给出的数量. 模块名称之前。

import inspect
import importlib
import ast


class Imports(ast.NodeVisitor):
    def visit_Import(self, node):
        print("In Import")
        for imp in node.names:
            if imp.asname is not None:
                print("module name = {}, alias = {}".format(imp.name, imp.asname))
            else:
                print("module name = {}".format(imp.name))
        print()

    def visit_ImportFrom(self, node):
        print("In ImportFrom")
        for imp in node.names:
            if imp.asname is not None:
                print("module = {}\nname = {}\nalias = {}\nlevel = {}\n".
                      format(node.module, imp.name, imp.asname, node.level))
            else:
                print("module = {}\nname = {}\nlevel = {}\n".
                      format(node.module, imp.name, node.level))
        print()

mod = "temp_test"
mod = importlib.import_module(mod)
p = ast.parse(inspect.getsource(mod))
Imports().visit(p)

输入:

from bisect import bisect_left as bs
import datetime
import time
import numpy as np

def foo():
    from re import findall

class Foo():
    def test(self):
        from re import compile as cp, finditer as ft

输出:

In ImportFrom
module = bisect
name = bisect_left
alias = bs
level = 0


In Import
module name = datetime

In Import
module name = time

In Import
module name = numpy, alias = np

In ImportFrom
module = re
name = findall
level = 0


In ImportFrom
module = re
name = compile
alias = cp
level = 0

module = re
name = finditer
alias = ft
level = 0

类Import(名称)

导入声明。 名称是别名节点的列表。

ImportFrom类(模块,名称,级别)

从x导入y表示。 module是'from'名称的原始字符串,没有任何前导点,对于诸如from这样的语句则为None。 导入foo。 level是保存相对导入级别的整数(0表示绝对导入)。

对于我来说, greentreesnakes文档至少比实际的ast文档本身对所有节点的功能以及如何使用ast模块有更好的解释。

您还可以使用直接传递模块或打开py文件并将内容传递给ast.parse:

with open("temp_test.py") as f:
    p = ast.parse(f.read(), filename="<ast>", mode="exec")
Imports().visit(p)

并传递模块:

import  temp_test

p = ast.parse(inspect.getsource(temp_test))
Imports().visit(p)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM