Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在模块中以文本方式查找导入的名称_Python_Regex_Python 2.7 - Fatal编程技术网

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

Python 如何在模块中以文本方式查找导入的名称,python,regex,python-2.7,Python,Regex,Python 2.7,我编写了一个名为buildRegex的方法,该方法给定一个名称(类型为str),返回一个regex对象,该对象从中查找。。。导入。。。Python模块中的name语句 例如,下面是buildRegex的预期行为: >>> regObj = buildRegex('foo') >>> regObj.search('from a import fool') is None True >>> regObj.search('from a import

我编写了一个名为
buildRegex
的方法,该方法给定一个名称(类型为
str
),返回一个
regex
对象,该对象从中查找
。。。导入。。。Python模块中的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
到目前为止,我所做的工作适用于上述所有示例(以及更多示例):

buildRegex
假设搜索的模块没有
SyntaxError
s,这是正常的

我的问题是,在查找导入的名称
foo
时,我还需要知道它是否是其他名称的别名。即,如果模块具有以下语句:

from a.b.c import bar as foo
我想知道什么是别名,在本例中,是
bar
。目前,由于正则表达式中的
断言lookaheads
,这是不可能的。最后,我的问题是:
如何重构正则表达式以避免丢失这些信息,例如,如果给定的名称是别名,那么它的别名就在
regex
之一中?

我建议不要编写复杂的正则表达式来解析导入,实际上可以使用
ast.parse
将源代码解析为抽象语法树,并从中查找名称。as
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
行中的整数给出了模块名称前的
数。

我建议不要编写复杂的正则表达式来解析导入,而是实际使用
ast.parse
将源代码解析为抽象语法树,并从中查找名称。as
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 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)
用法示例:

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
类导入(名称)

导入语句。名称是别名节点的列表

类导入自(模块、名称、级别)

表示从x导入y。模块是一个由“from”名称组成的原始字符串,不带任何前导点,对于诸如from之类的语句也不带前导点。输入foo。level是一个整数,表示相对导入的级别(0表示绝对导入)

对于我来说,这个文档至少比实际的ast文档本身对所有节点做什么以及如何使用ast模块有更好的解释

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

with open("temp_test.py") as f:
    p = ast.parse(f.read(), filename="<ast>", mode="exec")
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
类导入(名称)

导入语句。名称是别名节点的列表

类导入自(模块、名称、级别)

表示从x导入y。模块是一个由“from”名称组成的原始字符串,不带任何前导点,对于诸如from之类的语句也不带前导点。输入foo。level是一个整数,表示相对导入的级别(0表示绝对导入)

对于我来说,这个文档至少比实际的ast文档本身对所有节点做什么以及如何使用ast模块有更好的解释

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

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

表单当然可以使用regex进行解析,但考虑到可能有多行、多个导入逗号分隔等,您确定不想使用
ast.parse
?表单当然可以使用regex进行解析,但考虑到可能有多行、多个导入逗号分隔等,你确定你不想使用
ast.parse
?这个答案和@Antii's都是好的和正确的,但是由于链接非常有用,这个答案和@Antii's都是好的和正确的,但是由于链接非常有用,这个答案和@Antii's都是好的和正确的。