Python 3:检查字符串是否为导入命令

时间:2017-05-28 11:49:59

标签: python python-3.x

我想检查一个字符串 - 它是一个导入命令吗?我试过了

# Helper - analyses a string - is it an import string?
"""
fromlike   - from foo import bar
classic    - import foo
classic_as - import foo as baz
"""
def check_is_import(string):
    importname = ''
    fromlike   = False
    classic    = False
    classic_as = False
    if string[0:4] is 'from':
        fromlike = True
        importname = ''
    if not fromlike and (string[0:6] is 'import'):
        classic = True
        importname = string.split(' ')[1]
    if classic:
        commandlist = string.split(' ')
        if commandlist[2] is 'as':
            classic_as = True
            importname = commandlist[3]
            del commandlist
    if fromlike:
        return ('fromlike', importname)
    elif classic and (not classic_as):
        return ('classic', importname)
    elif classic_as:
        return ('classic_as', importname)
    else:
        return ('no_import', importname)

但它适用于" fromlike"进口。 (注意:我没有问过"为什么这些代码不起作用?",我只是在搜索解决方案)什么代码肯定能检测到所有导入?基本上我的代码需要一小部分字符串。如果[0:4]切片等于'from',则字符串为" fromlike import"。否则:如果[0:6]切片等于'import',则该字符串为"经典导入"。如果它检测到'as',它将找到伪名称。此函数必须返回一个元组,该元组包含索引0下的导入类型和索引1下的导入模块名称。

1 个答案:

答案 0 :(得分:2)

如果您想确保处理所有Python导入表单,请让 Python进行解析。使用ast.parse() function并使用生成的解析树;您将获得ImportImportFrom个对象:

  | Import(alias* names)
  | ImportFrom(identifier? module, alias* names, int? level)

每个alias都包含一个名称和可选标识符,用于将名称​​导入为

-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)

请注意,可以有多次导入!您可以导入classicfromlike,并且两者都可以导入多个名称。您的函数需要返回(type, name)元组的列表。对于无效输入,引发异常(ValueError非常适合):

import ast

def check_is_import(string):
    try:
        body = ast.parse(string).body
    except SyntaxError:
        # not valid Python
        raise ValueError('No import found')
    if len(body) > 1:
        # not a single statement
        raise ValueError('Multiple statements found')
    if not isinstance(body[0], (ast.Import, ast.ImportFrom)):
        raise ValueError('No import found')
    type_ = 'classic' if isinstance(body[0], ast.Import) else 'fromlike'
    results = []
    for alias in body[0].names:
        alias_type = type_
        if alias.asname:
            alias_type += '_as'
        results.append((alias_type, alias.asname or alias.name))
    return results

该方法应该重命名为extract_import_names(),因为这反映了它做得更好。

演示:

>>> check_is_import('from foo import bar')
[('fromlike', 'bar')]
>>> check_is_import('import foo')
[('classic', 'foo')]
>>> check_is_import('import foo as baz')
[('classic_as', 'baz')]
>>> check_is_import('from foo import bar, baz as spam, monty as python')
[('fromlike', 'bar'), ('fromlike_as', 'spam'), ('fromlike_as', 'python')]
>>> check_is_import('import foo as baz, baz, spam as ham')
[('classic_as', 'baz'), ('classic', 'baz'), ('classic_as', 'ham')]
>>> check_is_import('invalid python')
Traceback (most recent call last):
  File "<stdin>", line 3, in check_is_import
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/ast.py", line 35, in parse
    return compile(source, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 1
    invalid python
                 ^
SyntaxError: invalid syntax

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in check_is_import
ValueError: No import found
>>> check_is_import('import foo; import bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in check_is_import
ValueError: Multiple statements found
>>> check_is_import('1 + 1 == 2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in check_is_import
ValueError: No import found