从当前工作目录上方的目录导入模块 [英] Importing module from a directory above current working directory
问题描述
首先,有很多关于stackoverflow的解决方案,但是从我尝试过的解决方案中,没有一个起作用.我正在远程计算机(Linux)上工作.我正在使用ipython解释器在 dir-2/module_2.py
文件中制作原型.另外,我试图避免使用绝对路径,因为此远程计算机中的绝对路径又长又丑陋,并且我希望我的代码在下载时可以在其他计算机上运行.
我的目录结构如下:
/project-dir/-/dir-1/-/__ init__.py-/module_1.py-/dir-2/-/__ init__.py-/module_2.py-/module_3.py
现在,我想从 module_2
导入 module_1
.但是此stackoverflow帖子中提到的解决方案:链接使用
sys.path.append('../..')导入模块_2
不起作用.我收到错误消息: ModuleNotFoundError:没有名为"module_1"的模块
此外,在ipython解释器中,诸如 module_2
中的 import .module_3
之类的错误引发:
import .module_3^ SyntaxError:语法无效
点运算符也不应该在同一目录中工作.总的来说,我对导入机制感到很困惑.非常感谢您对最初问题的任何帮助!非常感谢!
为什么不起作用?
如果运行 module1.py
文件,并且要导入 module2
,则需要类似
sys.path.append("../dir-2")
如果使用 sys.path.append("../.."),则添加到路径的文件夹是包含
project-dir 的文件夹不是
module2.py`文件.
import .module_3
语法用于相对导入.如果您尝试执行 module2.py
并且其中包含 import .module_3
,则该代码将不起作用,因为您将 module2.py
用作脚本.要使用相对导入,您需要将 module2.py
和 module_3.py
都视为模块.也就是说,其他一些文件导入module2和module2使用此语法从module3导入一些东西.
关于如何进行的建议
解决这两个问题的一种可能的解决方案是组织项目的属性和(可选地,一个好主意)打包库(即,使代码可安装").然后,在安装库(在虚拟环境中工作)后,您就不需要 hacky sys.path
解决方案.您将可以从任何文件夹导入库.
此外,请勿将您的模块视为脚本(请勿运行您的模块).使用单独的python文件作为您的可执行文件"(或入口点),然后从那里导入您需要的所有内容.这样,您的 module * .py
文件中的相对导入将可以正常工作,并且您不会感到困惑.
可能是可能的目录结构
/project-dir/- 应用/-main.py-yourlib/-/__ init__.py-/dir-1/-/__ init__.py-/module_1.py-/dir-2/-/__ init__.py-/module_2.py-/module_3.py
请注意, yourlib
文件夹以及子文件夹包含一个 __ init __.py
文件.使用这种结构,您只需运行 main.py
(名称不必为 main.py
).
情况1:您不想打包您的库
如果您不想打包您的库,则可以在 main.py
中添加 sys.path.append("../")
将 project-dir/
文件夹添加到路径.这样,您的 yourlib
库将可导入",在 main.py
中.您可以从liblib导入module_2 中执行之类的操作,它将正常工作(并且
module_2
可以使用相对导入).另外,您也可以直接将 main.py
放在 project-dir/
文件夹中,而无需在以下位置更改 sys.path
因为 project-dir/
将是工作目录",在这种情况下.
请注意,您还可以在 project-dir
中包含一个 tests
文件夹,并且要运行测试文件,您可以执行与运行 main相同的操作.py
.
情况2:您想打包您的库
先前的解决方案已经解决了您的问题,但加倍努力会带来一些好处,例如依赖管理,并且无论您身在何处都无需更改 sys.path
.打包您的库有几种选择,由于其简单性,我将使用诗歌显示一个选择.>
安装诗歌后,您可以在终端中运行以下命令来创建新项目
诗歌新的mylib
这将创建以下文件夹结构
mylib/-README.rst-mylib/-__init__.py-pyproject.toml-测试
然后,您可以根据需要添加 apps
文件夹,以及 mylib/
中的子文件夹(每个文件夹都包含一个 __ init __.py
文件)).
pyproject.toml
文件指定依赖项和项目元数据.您可以手动编辑和/或使用诗歌添加新的依存关系,例如
诗歌添加熊猫诗歌添加--dev mypy
例如,
将 pandas
添加为依赖项,将 mypy
添加为开发依赖项.之后,您可以运行
诗歌构建
创建一个虚拟环境并在其中安装您的库.您可以使用 poetry shell
激活虚拟环境,并且可以从任何地方导入库.请注意,您可以更改库文件,而无需再次运行 poetry build
.
最后,如果您想在PyPi中发布您的库,以供所有人查看,您可以使用
<代码>诗歌发布--username your_pypi_username --password _passowrd_
TL;DR
对您执行的脚本使用有条理的项目结构,并留有清晰的位置.特别是,如果您执行的脚本位于模块所在文件夹的外部,则更好.另外,请勿将模块作为脚本运行(否则您不能使用相对导入).
First of all, there are a bunch of solutions on stackoverflow regarding this but from the ones I tried none of them is working. I am working on a remote machine (linux). I am prototyping within the dir-2/module_2.py
file using an ipython interpreter. Also I am trying to avoid using absolute paths as the absolute path in this remote machine is long and ugly, and I want my code to run on other machines upon download.
My directory structure is as follows:
/project-dir/
-/dir-1/
-/__ init__.py
-/module_1.py
-/dir-2/
-/__ init__.py
-/module_2.py
-/module_3.py
Now I want to import module_1
from module_2
. However the solution mentioned in this stackoverflow post: link of using
sys.path.append('../..')
import module_2
Does not work. I get the error: ModuleNotFoundError: No module named 'module_1'
Moreover, within the ipython interpreter things like import .module_3
within module_2
throws error:
import .module_3 ^ SyntaxError: invalid syntax
Isn't the dot operator supposed to work within the same directory as well. Overall I am quite confused by the importing mechanism. Any help with the initial problem is greatly appreciated! Thanks a lot!
Why it didn't work?
If you run the module1.py
file and you want to import module2
then you need something like
sys.path.append("../dir-2")
If you use sys.path.append("../..") then the folder you added to the path is the folder containing
project-dirand there is not
module2.py` file inside it.
The syntax import .module_3
is for relative imports. if you tried to execute module2.py
and it contains import .module_3
it does not work because you are using module2.py
as a script. To use relative imports you need to treat both module2.py
and module_3.py
as modules. That is, some other file imports module2 and module2 import something from module3 using this syntax.
Suggestion on how you can proceed
One possible solution that solves both problems is property organizing the project and (optionally, ut a good idea) packaging your library (that is, make your code "installable"). Then, once your library is installed (in the virtual environment you are working) you don't need hacky sys.path
solutions. You will be able to import your library from any folder.
Furthermore, don't treat your modules as scripts (don't run your modules). Use a separate python file as your "executable" (or entry point) and import everything you need from there. With this, relative imports in your module*.py
files will work correctly and you don't get confused.
A possible directory structure could be
/project-dir/
- apps/
- main.py
- yourlib/
-/__ init__.py
-/dir-1/
-/__ init__.py
-/module_1.py
-/dir-2/
-/__ init__.py
-/module_2.py
-/module_3.py
Notice that the the yourlib
folder as well as subfolders contain an __init__.py
file. With this structure, you only run main.py
(the name does not need to be main.py
).
Case 1: You don't want to package your library
If you don't want to package your library, then you can add sys.path.append("../")
in main.py
to add "the project-dir/
folder to the path. With that your yourlib
library will be "importable" in main.py
. You can do something like from yourlib import module_2
and it will work correctly (and module_2
can use relative imports). Alternatively, you can also directly put main.py
in the project-dir/
folder and you don't need to change sys.path
at all, since project-dir/
will be the "working directory" in that case.
Note that you can also have a tests
folder inside project-dir
and to run a test file you can do the same as you did to run main.py
.
Case 2: You want to package your library
The previous solution already solves your problems, but going the extra mile adds some benefits, such as dependency management and no need to change sys.path
no matter where you are. There are several options to package your library and I will show one option using poetry due to its simplicity.
After installing poetry, you can run the command below in a terminal to create a new project
poetry new mylib
This creates the following folder structure
mylib/
- README.rst
- mylib/
- __init__.py
- pyproject.toml
- tests
You can then add the apps
folder if you want, as well as subfolders inside mylib/
(each with a __init__.py
file).
The pyproject.toml
file specifies the dependencies and project metadata. You can edit it by hand and/or use poetry to add new dependencies, such as
poetry add pandas
poetry add --dev mypy
to add pandas
as a dependency and mypy
as a development dependency, for instance. After that, you can run
poetry build
to create a virtual environment and install your library in it. You can activate the virtual environment with poetry shell
and you will be able to import your library from anywhere. Note that you can change your library files without the need to run poetry build
again.
At last, if you want to publish your library in PyPi for everyone to see you can use
poetry publish --username your_pypi_username --password _passowrd_
TL; DR
Use an organized project structure with a clear place for the scripts you execute. Particularly, it is better if the script you execute is outside the folder with your modules. Also, don't run a module as a script (otherwise you can't use relative imports).
这篇关于从当前工作目录上方的目录导入模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!