Python 依赖分析库

6 投票
1 回答
908 浏览
提问于 2025-04-16 20:15

我需要一种方法,在运行时找到我每个Python包的子模块之间的依赖关系,这样我才能按正确的顺序初始化它们(可以看看我之前的解决方案这里,不过效果不太好)。最开始我用了Python的标准模块modulefinder,但是速度太慢了(每个模块大约需要1-2秒)。

接下来,我尝试分析每个模块的全局变量,看看这些全局变量中每个子模块依赖于哪个子模块。(这是我现在的解决方案编辑:我现在有了更好的解决方案 - 请看我的回答)。这个算法比modulefinder快多了(每个模块少于200毫秒),但它只适用于相对导入,而不支持完全限定的导入方式,这让我觉得不太能接受。

所以,我需要的是:

  • 一个比modulefinder更快的替代方案
  • 一个替代的算法

注意:我在每个模块开始时调用我的依赖分析器,像这样:

# File my_package/module3.py

import my_package.module1 # Some misc. module
import my_package.module2 # Some other misc. module
import my_package.dependency_analyzer

my_package.dependency_analyzer.gendeps()

(希望这对你有帮助。)

谢谢!

编辑:我现在有了解决方案 - 请看我的回答。

1 个回答

3

我觉得我找到了自己问题的解决办法 :)

下面是关于上面提到的dependency_analyzer模块应该包含的内容:

import sys
from sys import _getframe as getframe
import atexit

examined_modules = []

def gendeps():
    """Adds the calling module to the initialization queue."""
    # Get the calling module's name, and add it to the intialization queue
    calling_module_name = getframe(1).f_globals['__name__']
    examined_modules.append(calling_module_name)

def init():
    """Initializes all examined modules in the correct order."""

    for module in examined_modules:
        module = sys.modules[module]
        if hasattr(module, 'init'):
            module.init()
        if hasattr(module, 'deinit'):
            # So modules get de-initialized in the correct order,
            # as well
            atexit.register(module.deinit)

在每个模块的开始部分(所有导入语句之后 - 这一点很重要),会调用gendeps。这个算法之所以有效,是因为每次导入一个模块时,都会执行对gendeps的调用。不过,由于你自己的模块中所有的导入语句都放在了调用gendeps之前,所以依赖关系最少的模块会最先放入初始化队列,而依赖关系最多的模块则会最后放入初始化队列。

撰写回答