【问题标题】:Importing Python modules when there is a sibling directory with the same name存在同名同级目录时导入 Python 模块
【发布时间】:2021-10-29 20:53:30
【问题描述】:

我的项目结构如下:

python-test » tree
.
├── asdf
│   ├── __init__.py
│   ├── mycode2.py
│   ├── mycode.py
│   └── scripts
│       └── __init__.py
├── __init__.py
└── scripts
    ├── __init__.py
    └── mymod.py

asdf/mycode.py 包含:

import scripts.mymod

scripts/mymod.py 包含:

print('hello world')

所有__init__.pys 都是空的。

我想导入scripts.mymod

我正在运行 asdf/mycode.py 失败,因为它正在查看 asdf/scripts 而不是 mymod 的根 scripts 文件夹。

> PYTHONPATH=: python asdf/mycode.py
Traceback (most recent call last):
  File "asdf/mycode.py", line 1, in <module>
    import scripts.mymod
ModuleNotFoundError: No module named 'scripts.mymod'

作为一种解决方法,我可以手动修改路径,我已经在asdf/mycode2.py 中完成了。

import sys
sys.path = [p for p in sys.path if 'asdf' not in p]
import scripts.mymod

这可以正常工作:

> PYTHONPATH=: python asdf/mycode2.py
hello world

有没有办法在asdf/mycode.py 中导入scripts.mymod 无需手动修改sys.path,并且无需更改必须设置为:PYTHONPATH? p>

【问题讨论】:

  • 您可以在项目目录中使用主入口点。 python-test/main.py 如果您从主目录运行代码。您可以使用from asdf.scripts import ...from scripts import mymod 导入。

标签: python path python-import


【解决方案1】:

TL;DR

Python 导入既奇怪又麻烦,您最好在目录顶部创建一个入口点或使用工具来处理路径操作。

Python 导入

Python 有两种不同的处理导入的方式,第一种是标准的:import numpy as np,它会针对环境 PYTHONPATH 进行解析,直到找到请求的模块。该路径中包含当前正在执行的文件的目录,您在示例中看到,您需要手动将其从 sys.path 中删除。

python 处理导入的另一种方式是通过相对路径,它总是以. 开头,如from . import aimport .afrom .. import b。不幸的是,如果它们所在的文件直接运行,则相对导入起作用(如果您在一个模块中有两个文件,其中一个导入一个对象,则会发生这种情况来自另一个,但它们都旨在由外部脚本导入)。这是因为 python 使用内置的 name 全局来解析相对路径,如果文件直接从 shell 运行,则会将其覆盖为 "__main__"

考虑一个文件结构:

.
├── a.py
└── b.py

a.py 在哪里

import b

b.py

print(__name__)

如果你运行:

python3 b.py    # prints "__main__"
python3 a.py    # prints "b"

因此,如果您希望能够从 asdf/mycode2.py 导入 scripts/mymod.py,您可以将导入更改为:

from .. import scripts.mymod

但是,如果您这样做,您将无法直接运行 asdf/mycode2.py 文件,您需要在其他地方创建第三个文件以导入 asdf/mycode2.py 并运行第三个文件脚本(这些文件称为入口点)。例如:

python-test » tree
.
├── asdf
│   ├── __init__.py
│   ├── mycode2.py
│   ├── mycode.py
│   └── scripts
│       └── __init__.py
├── __init__.py
├── entrypoint.py
└── scripts
    ├── __init__.py
    └── mymod.py

entrypoint.py 在哪里

import asdf.mycode2

另一种方法

另一种方法是开发一个工具来处理 python 的 sys.path 以允许相对导入,即使当前文件正在运行 "__main__"。完全披露,我目前正在开发一个基于 nodejs 的 require 函数的工具,称为 repyrer,它是 pip-installable

pip3 install repyrer

它允许你做这种事情:

from repyrer import repyre

mymod = repyre('../scripts/mymod')

即使你直接运行文件也可以。

希望有帮助!

【讨论】:

    猜你喜欢
    • 2019-06-19
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2014-11-16
    相关资源
    最近更新 更多