python - 存在同名同级目录时导入 Python 模块
问题描述
我有一个项目结构如下:
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__.py
s 都是空的。
我想导入scripts.mymod
.
我正在运行asdf/mycode.py
失败,因为它正在查看内部asdf/scripts
而scripts
不是mymod
.
> 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
scripts.mymod
有没有一种方法可以在asdf/mycode.py
不手动修改sys.path
且不更改PYTHONPATH
必须设置为的情况下导入:
?
解决方案
TL;博士
Python 导入既奇怪又麻烦,您最好在目录顶部创建一个入口点或使用工具来处理路径操作。
Python 导入
Python 有两种不同的处理导入的方法,第一种是标准的: import numpy as np
,它是针对环境 PYTHONPATH 解析的,直到找到请求的模块。该路径中包含当前正在执行的文件的目录,您在示例中看到,您需要从sys.path
.
python 处理导入的另一种方式是通过相对路径,它总是以.
likefrom . import a
或import .a
or 开头from .. import b
。不幸的是,相对导入仅在它们所在的文件没有直接运行时才有效(如果您在一个模块中有两个文件,其中一个从另一个导入对象,但它们都打算由 和外部脚本)。这是因为 python 使用内置名称global 来解析相对路径,如果文件直接从 shell 运行,则会将其覆盖为"__main__"
.
考虑一个文件结构:
.
├── a.py
└── b.py
a.py
在哪里
import b
并且b.py
是
print(__name__)
如果你运行:
python3 b.py # prints "__main__"
python3 a.py # prints "b"
因此,如果您希望能够导入scripts/mymod.py
from asdf/mycode2.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
另一种方法
另一种方法是开发一个工具来处理操作 pythonsys.path
以允许相对导入,即使当前文件正在运行"__main__"
。完全披露,我目前正在开发一个基于 nodejsrequire
功能的工具,称为repyrer,它是 pip-installable
pip3 install repyrer
它允许你做这样的事情:
from repyrer import repyre
mymod = repyre('../scripts/mymod')
即使您直接运行文件,它也可以工作。
希望有帮助!
推荐阅读
- ios - Swift 4 中 Firestore 应用的存储下载成本太高
- java - NestedScrollView 不能强制转换为 android.support.constraint.ConstraintLayout
- python - TensorFlow 中的自定义卷积层
- c - rand%100 在 C 中生成随机数的问题
- templates - 如何在 TWIG 模型中显示当前用户的图片?
- numpy - 如何将大型 CSV 加载到 keras 模型中?
- msal - MSAL stateMismatch 的目的是什么
- asp.net-mvc - 什么是制作网站的最佳方式不需要注册,但我需要为管理员制作登录页面
- c# - 如何修复此 IF 语句?
- regex - Perl:匹配后打印所有行