在具有大量嵌套文件夹的项目中存在相对导入问题。

huangapple go评论73阅读模式
英文:

Problem with relative imports in project with lot of nested folders

问题

抱歉,您的问题似乎很基础。我对Python相对较新,目前正在学习这门语言。
我想在我的项目中使用相对路径来引用文件(例如配置文件、日志文件等)。在网上搜索时,我发现将一个文件放在根目录或一级目录中,其中包含一个类似于ROOT_DIR变量的内容,可以导入并在项目的其余部分中使用,这是一个良好的实践。在给定的代码结构下,我在实施这个解决方案时遇到了问题:

root_dir
├── config
│   ├── config.ini
│   ├── definitions.py
├── libs
│   ├── lib_1
│   │   ├── A.py
│   │   └── test
│   │       └── test_A.py
│   ├── lib_2
│   │   ├── B.py
│   │   └── test
│   │       └── test_B.py
├── main.py

definitions.py文件的内容是:

import os
ROOT_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))

如果我在距离definitions.py一级的main.py中使用ROOT_DIR,这可以正常工作,但是如果我在A.pyB.py中使用ROOT_DIR,使用from config.definitions import ROOT_DIR导入时就会出现问题。
我尝试在每个目录中添加了__init__.py文件,但没有任何效果。PyCharm似乎没问题,并且识别了这个导入,但如果我从终端运行根文件夹或lib_1/lib_2中的A.pyB.py,就会引发ModuleNotFoundError

有人可以向我解释如何在项目的任何子文件夹中使用相对导入来实现这种行为吗?有什么Pythonic的方法吗?
非常感谢您们!

英文:

Apologies in advance if my question seems basic. I'm relatively new to Python and I'm currently in the process of learning the language.
I want to use relative paths in my project to refer to files (e.g. config files, log files etc); browsing online i found that it is good practice to have a file in the root directory or in a first level directory that contains a sort of ROOT_DIR variable that you can import and use in the rest of the project. Given the following code structure, I'm having problems implementing this solution:

root_dir
├── config
│   ├── config.ini
│   ├── definitions.py
├── libs
│   ├── lib_1
│   │   ├── A.py
│   │   └── test
│   │       └── test_A.py
│   ├── lib_2
│   │   ├── B.py
│   │   └── test
│   │       └── test_B.py
├── main.py

The content of the definitions.py file is:

import os
ROOT_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))

This works fine if I use ROOT_DIR from within the main.py that is one level above definitions.py but does not work if I use ROOT_DIR from, say, A.py or B.py, doing from config.definitions import ROOT_DIR.
I tried adding __init__.py files to every directory but nothing. PyCharm seems to be fine and recognizes the import but if I run A.py or B.py from the terminal either from the root folder or from lib_1/lib_2, ModuleNotFoundError is fired.

Can anyone explain to me how can I achieve this behaviour using relative imports from any subfolder of the project? What is the pythonic way to do so?
Thank you all in advance

答案1

得分: 1

你遇到的问题源于你运行Python脚本的方式。当你直接运行Python脚本时,Python的模块搜索路径(sys.path)从脚本所在的目录开始。因此,如果你在lib_1lib_2中尝试直接运行A.pyB.py,Python将无法找到config模块,因为它既不在脚本的目录中,也不在PYTHONPATH中。

这是解决方案:不要直接运行A.pyB.py,而应该使用Python的-m标志将它们作为模块从项目的根目录开始执行。下面是如何操作:

  1. 打开终端并导航到项目的根目录(root_dir)。
  2. 使用以下命令运行你的Python模块:
python -m libs.lib_1.A
python -m libs.lib_2.B

这里,-m标志告诉Python将模块作为脚本运行,Python将能够正确解析相对导入from config.definitions import ROOT_DIR

这是一种处理模块组织的Python方式,它使你的代码更易维护,更具可移植性,无需担心操作sys.path或特定操作系统的路径。

还要记得在要让Python识别为包的每个目录中添加一个空的__init__.py文件。这包括root_dir/configroot_dir/libsroot_dir/libs/lib_1root_dir/libs/lib_2以及test子目录。这些文件可以为空,但必须存在。

英文:

The issue you're experiencing comes from how you're running your Python scripts. When you run a Python script directly, Python's module search path (sys.path) begins from the script's directory. As a result, if you're inside lib_1 or lib_2 and try to run A.py or B.py directly, Python won't be able to find the config module, as it's neither in the script's directory nor in the PYTHONPATH.

Here is the solution: instead of running A.py or B.py directly, you should execute them as modules using Python's -m flag, starting from the root directory of your project. Here's how you can do that:

  1. Open your terminal and navigate to the root directory of your project (root_dir).
  2. Run your Python modules with the following commands:
python -m libs.lib_1.A
python -m libs.lib_2.B

Here, the -m flag tells Python to run the module as a script, and Python will be able to correctly resolve the relative import from config.definitions import ROOT_DIR.

This is a Pythonic way of dealing with module organization and it makes your code more maintainable and portable without having to worry about manipulating sys.path or about operating system specific paths.

Also, remember to add an empty __init__.py file in each directory that you want Python to recognize as a package. This includes root_dir/config, root_dir/libs, root_dir/libs/lib_1, root_dir/libs/lib_2, and the test subdirectories. These files can be empty, but they need to be present.

huangapple
  • 本文由 发表于 2023年6月8日 06:57:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427584.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定