Python`pkgutil.get_data`中断将来的导入

请考虑以下程序包结构:

.
├── module
│   ├── __init__.py
│   └── submodule
│       ├── attribute.py
│       ├── data.txt
│       └── __init__.py
└── test.py

以及以下代码:

import pkgutil
data = pkgutil.get_data('module.submodule','data.txt')
import module.submodule.attribute
retval = module.submodule.attribute.hello()

运行此命令将引发错误:

Traceback (most recent call last):
  File "test.py",line 7,in <module>
    retval = module.submodule.attribute.hello()
AttributeError: module 'module' has no attribute 'submodule'

但是,如果运行以下命令:

import pkgutil
import module.submodule.attribute
data = pkgutil.get_data('module.submodule','data.txt')
retval = module.submodule.attribute.hello()

import pkgutil
import module.submodule.attribute
retval = module.submodule.attribute.hello()

它工作正常。

为什么运行pkgutil.get_data会中断以后的导入?

XIAOYING178 回答:Python`pkgutil.get_data`中断将来的导入

首先,这是一个很好的问题,也是学习python导入系统新知识的绝佳机会。因此,让我们深入研究吧!

如果我们查看the implementation of pkgutil.get_data,将会看到类似这样的内容:

def get_data(package,resource):
    spec = importlib.util.find_spec(package)
    if spec is None:
        return None
    loader = spec.loader
    if loader is None or not hasattr(loader,'get_data'):
        return None
    # XXX needs test
    mod = (sys.modules.get(package) or
           importlib._bootstrap._load(spec))
    if mod is None or not hasattr(mod,'__file__'):
        return None

    # Modify the resource name to be compatible with the loader.get_data
    # signature - an os.path format "filename" starting with the dirname of
    # the package's __file__
    parts = resource.split('/')
    parts.insert(0,os.path.dirname(mod.__file__))
    resource_name = os.path.join(*parts)
    return loader.get_data(resource_name)

问题的答案在代码的这一部分:

    mod = (sys.modules.get(package) or
           importlib._bootstrap._load(spec))

它将查看已经加载的软件包,如果我们要查找的软件包(在本示例中为module.submodule)存在,它将使用它,如果不存在,则尝试使用importlib._bootstrap._load加载该软件包。

所以让我们看一下implementation of importlib._bootstrap._load来看看发生了什么。

def _load(spec):
    """Return a new module object,loaded by the spec's loader.
    The module is not added to its parent.
    If a module is already in sys.modules,that existing module gets
    clobbered.
    """
    with _ModuleLockManager(spec.name):
        return _load_unlocked(spec)

好吧,就在那里!文档说“模块未添加到其父级。”

这意味着submodule模块已加载,但未添加到module模块中。因此,当我们尝试通过submodule访问module时,没有连接,因此AtrributeError

get_data方法使用此函数很有意义,因为它只需要包中的其他文件,而无需导入整个包并将其添加到其父级和其父级的父级中,并且等等。

要亲自查看它,我建议使用调试器并设置一些断点。然后,您可以逐步了解发生的情况。

本文链接:https://www.f2er.com/2905114.html

大家都在问