You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何捕获包括from...import在内的所有导入语句?

How to Detect All Python Import Types (Including from...import)

The inspect module falls short here because it only looks at the runtime state of your code—if you use from os.path import basename, the os.path module might not be present in the global namespace (only basename is), so inspect can't pick it up. To capture every type of static import, you need to parse your code's Abstract Syntax Tree (AST) directly, which lets you analyze the source code structure before it's executed.

Here's a complete solution that captures:

  • Regular imports (e.g., import os)
  • Aliased imports (e.g., import numpy as np)
  • from...import of module members (e.g., from os.path import basename, join)
  • from...import of submodules (e.g., from sklearn import metrics)
  • Aliased from...import (e.g., from os.path import join as path_join)

Step-by-Step Implementation

First, we'll use Python's built-in ast module to parse the source code and traverse all import-related nodes:

import ast
from typing import List, Dict, Union

def collect_imports(file_path: str) -> Dict[str, List[Union[str, Dict[str, str]]]]:
    """
    Collect all imports from a Python file, including from...import statements.
    
    Returns a dictionary with two keys:
    - 'imports': List of regular imports (with aliases if present)
    - 'from_imports': List of from...import entries, each containing module and imported names
    """
    imports = []
    from_imports = []
    
    with open(file_path, 'r', encoding='utf-8') as f:
        source_code = f.read()
    
    # Parse the source code into an AST
    tree = ast.parse(source_code)
    
    # Traverse all nodes in the AST
    for node in ast.walk(tree):
        # Handle regular imports (e.g., import os, import numpy as np)
        if isinstance(node, ast.Import):
            for alias in node.names:
                import_entry = {
                    'module': alias.name,
                    'alias': alias.asname if alias.asname else None
                }
                imports.append(import_entry)
        
        # Handle from...import statements (e.g., from os.path import basename, join as path_join)
        elif isinstance(node, ast.ImportFrom):
            # The parent module (e.g., 'os.path' for from os.path import ...)
            parent_module = node.module if node.module else ''
            # Handle relative imports (e.g., from .utils import helper)
            if node.level > 0:
                parent_module = '.' * node.level + parent_module
            
            imported_names = []
            for alias in node.names:
                name_entry = {
                    'name': alias.name,
                    'alias': alias.asname if alias.asname else None
                }
                imported_names.append(name_entry)
            
            from_imports.append({
                'parent_module': parent_module,
                'imported_names': imported_names
            })
    
    return {
        'imports': imports,
        'from_imports': from_imports
    }

Example Usage

Suppose you have a file sample_imports.py with the following code:

import os
import numpy as np
from os.path import basename, join as path_join
from sklearn import metrics
from .local_module import helper_func

Running collect_imports('sample_imports.py') will return:

{
    'imports': [
        {'module': 'os', 'alias': None},
        {'module': 'numpy', 'alias': 'np'}
    ],
    'from_imports': [
        {
            'parent_module': 'os.path',
            'imported_names': [
                {'name': 'basename', 'alias': None},
                {'name': 'join', 'alias': 'path_join'}
            ]
        },
        {
            'parent_module': 'sklearn',
            'imported_names': [{'name': 'metrics', 'alias': None}]
        },
        {
            'parent_module': '.local_module',
            'imported_names': [{'name': 'helper_func', 'alias': None}]
        }
    ]
}

Key Notes

  • Handles Relative Imports: The code accounts for relative imports (like from .utils import ...) by prepending the appropriate number of dots based on node.level.
  • Captures Aliases: Both module aliases (e.g., import numpy as np) and member aliases (e.g., from os.path import join as path_join) are recorded.
  • Static Analysis Only: This approach won't catch dynamic imports (e.g., importlib.import_module('os')), since those are resolved at runtime. For dynamic imports, you'd need additional runtime inspection combined with AST parsing.
  • No Runtime Execution: Since we're parsing the source code directly, there's no risk of executing the code (which is great for analyzing untrusted code).

Why This Works Better Than inspect

The inspect module relies on examining the live module's namespace. When you use from X import Y, only Y is added to the namespace—not the full X module (unless you also imported X separately). AST parsing looks at the actual source code structure, so it can detect every import statement exactly as it's written, regardless of how it affects the runtime namespace.

内容的提问来源于stack exchange,提问作者code base 5000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:56:31