【问题标题】:Module not recognising root directory for Python imports模块无法识别 Python 导入的根目录
【发布时间】:2020-10-14 13:40:26
【问题描述】:

我有一个使用 MicroKernel 模式的 Python 项目,我希望每个模块都完全独立。我将每个模块导入内核并且工作正常。但是,当我在一个模块中时,我希望模块的根目录是模块目录。这是不工作的部分。

项目结构;

.
├── requirements.txt
├── ...
├── kernel
│   ├── config.py
│   ├── main.py
│   ├── src
│   │   ├── __init__.py
│   │   ├── ...
│   └── test
│       ├── __init__.py
│       ├── ...
├── modules
│   └── img_select
│       ├── __init__.py
│       ├── config.py
│       ├── main.py
│       └── test
│           ├── __init__.py
│           └── test_main.py

如果我在modules/img_select/test/test_main.py 中导入from main import somefunction,我会收到以下错误:

ImportError: cannot import name 'somefunction' from 'main' (./kernel/main.py)

所以它显然没有将modules/img_select视为模块的根,这导致了以下问题:

如何在模块中设置导入的根?

一些附加信息,我确实在配置文件中添加了带有 sys.path 的路径; 内核/config.py;

import os
import sys

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
MODULES_DIR = os.path.join(ROOT_DIR, '../modules')

sys.path.insert(0, os.path.abspath(MODULES_DIR))

模块/img_select/config.py;

import os
import sys

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(ROOT_DIR))

而我的python版本是3.7.3

我确实意识到那里有很多 excellent resources,但我尝试了大多数方法,但似乎无法让它发挥作用。

【问题讨论】:

    标签: python-3.x python-import


    【解决方案1】:

    我不确定您要从哪个main 导入。我认为 python 也对路径感到困惑。 test_main.py 如何选择运行哪个 main?通常,当您有一个包(带有__init__.py 的目录)时,您从包而不是单个模块中导入。

    # test_main.py
    # If img_select is in the path and has __init__.py
    from img_select.main import somefunction
    

    如果img_select 没有__init__.py 并且路径中有img_select,则可以从main 导入。

    # test_main.py
    # If img_select is in the path without __init__.py
    from main import somefunction
    

    在您的情况下,我不知道您如何尝试指示要从哪个 main.py 导入。您如何导入和调用正确的config.py

    您也许可以使用os.chdir 更改当前目录。 我认为你的主要问题是img_select 是一个带有__init__.py 的包。当 main 位于包中时,Python 不喜欢使用 from main import ... Python 期望使用 from img_select.main import ...

    工作目录

    如果您在目录modules/img_select/test/ 中并调用python test_main.py,则此目录称为您的工作目录。您的工作目录位于您调用python 的任何位置。如果您在顶级目录(requirements.txt 所在的位置)并调用python modules/img_select/test/test_main.py,那么顶级目录就是工作目录。 Python 使用这个工作目录作为路径。

    如果kernel 有一个__init__.py,那么python 将从顶级目录中找到kernel。如果kernel 不是一个包,那么您需要将kernel 目录添加到路径中,以便python 看到kernel/main.py。一种方法是按照您的建议修改 sys.path 或 PYTHONPATH。但是,如果您的工作目录是 modules/img_select/test/,那么您必须上几个目录才能找到正确的路径。

    # test_main.py
    import sys
    
    TEST_DIR = os.path.dirname(__file__)  # modules/img_select/test/
    IMG_DIR = os.path.dirname(TEST_DIR)
    MOD_DIR = os.path.dirname(IMG_DIR)
    KERNEL_DIR = os.path.join(os.path.dirname(MOD_DIR), 'kernel')
    sys.path.append(KERNEL_DIR)
    
    from main import somefunction
    

    如果您的顶级目录(requirements.txt 所在的位置)是您的工作目录,那么您仍然需要将 kernel 添加到路径中。

    # modules/img_select/test/test_main.py
    import sys
    sys.path.append('kernel')
    

    正如您所见,这可能会根据您的工作目录而改变,您必须手动修改每个正在运行的文件。你可以像你正在做的那样用 abspath 来解决这个问题。但是,每个文件都需要修改路径。我不建议手动更改路径。

    Python 路径可能很痛苦。我建议建立一个图书馆。 您只需创建一个setup.py 文件即可将kernel 或其他软件包安装为库。 setup.py 文件应与requirements.txt 处于同一级别

    # setup.py
    """
    setup.py - Setup file to distribute the library
    
    See Also:
        * https://github.com/pypa/sampleproject
        * https://packaging.python.org/en/latest/distributing.html
        * https://pythonhosted.org/an_example_pypi_project/setuptools.html
    """
    from setuptools import setup, Extension, find_packages
    
    setup(name='kernel',
          version='0.0.1',
          # Specify packages (directories with __init__.py) to install.
          # You could use find_packages(exclude=['modules']) as well
          packages=['kernel'],  # kernel needs to have __init__.py
          include_package_data=True,
          )
    

    kernel 目录需要__init__.py。如果您仍在使用该库,请将其安装为可编辑的。在具有setup.py 文件的顶级目录中调用pip install -e .

    安装库后,python 会将kernel 目录复制或链接到其site-packages 路径中。现在您的test_main.py 文件只需要正确导入内核

    # test_main.py
    from kernel.main import somefunction
    
    somefunction()
    

    自定义 init.py

    ​​>

    由于内核现在有一个__init__.py,您可以通过导入kernel来控制可用的功能

    # __init__.py
    # The "." indicates a relative import
    from .main import somefunction
    from .config import ...
    
    try:
        from .src.mymodule import myfunc
    except (ImportError, Exception):
        def myfunc(*args, **kwargs):
            raise EnvironmentError('Function not available. Missing dependency "X".')
    

    更改 __init__.py 后,您可以从内核而不是 kernel.main 导入

    # test_main.py
    from kernel import somefunction
    
    somefunction()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 2021-02-26
      • 1970-01-01
      相关资源
      最近更新 更多