如何使用相对路径导入脚本?
How to import script with relative path?
我有以下目录结构
project/
bin/
script
stuff/
__init__.py
mainfile.py
在脚本内部,我有以下命令来启用命令行执行:
#!/usr/bin/env python
from stuff import mainfile
这行得通,但我原以为需要跳上一级...
from ..stuff import mainfile
或
from project.stuff import mainfile
我在这里错过了什么?
您需要先将父目录添加到sys.path
。尝试以下操作:
# This is a file in bin/ directory.
this_file_path = os.path.dirname(__file__)
sys.path.append(os.path.join(this_file_path, '..'))
import stuff.mainfile
实际上 none 您的示例应该开箱即用。
让我们稍微修改一下bin/script.py
:
#! /usr/bin/env python
import sys
print sys.path
from stuff import mainfile
这应该会产生类似于
的结果
['.../project/bin', ...]
Traceback (most recent call last):
File "bin/script.py", line 6, in <module>
from stuff import mainfile
ImportError: No module named stuff
只有the directory of the script(不是当前目录)自动添加到sys.path
:
As initialized upon program startup, the first item of this list, path[0]
, is the directory containing the script that was used to invoke the Python interpreter.* If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0]
is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH
.
因此 sys.path
上没有 stuff
模块。我不确定您的环境设置,但这是没有设置其他参数时的规范结果(例如 PYTHONPATH
)。
同样,
from ..stuff import mainfile
会产生经典ValueError: Attempted relative import in non-package
。您被告知您只能相对于实际模块进行相对导入。由于内部 script
..
不引用模块(因为脚本本身可以说是顶级模块),相对导入在这里不起作用。从 Python 的角度来说,脚本之上没有模块,因此 ..
在脚本的上下文中使用时不指代有形的东西。
请注意,这也意味着它 不 有助于仅通过删除 __init__.py
标记将 project
和 project/bin
放入模块本身文件。相对导入到脚本的 parent 只有当脚本的父级实际上是 python 有一个概念的东西时才有可能。
这就是 -m
命令行开关存在的原因之一,使得从命令行 运行 模块成为可能。例如,给定上面的相对 import
python -m project.bin.script
可以解决问题,但前提是从正确的目录 (projectdir/..) 执行。
这个问题更严重
from project.stuff import mainfile
因为 project
目录仅在您从 project
上面的目录启动脚本时自动位于 sys.path
和 不指定运行:
的主脚本
cd <projectdir>/..
python -m project.bin.script
# works
cd <projectdir>
python -m bin.script
# does not work, because `sys.path` starts with <projectdir>
# and it's `stuff.mainfile` now, not `project.stuff.mainfile`.
如果您想在脚本中从 project
导入模块,请根据您的需要修正 sys.path
:
import sys
import os
sys.path.insert(0, os.path.dirname(sys.path[0]))
from stuff import mainfile
我有以下目录结构
project/
bin/
script
stuff/
__init__.py
mainfile.py
在脚本内部,我有以下命令来启用命令行执行:
#!/usr/bin/env python
from stuff import mainfile
这行得通,但我原以为需要跳上一级...
from ..stuff import mainfile
或
from project.stuff import mainfile
我在这里错过了什么?
您需要先将父目录添加到sys.path
。尝试以下操作:
# This is a file in bin/ directory.
this_file_path = os.path.dirname(__file__)
sys.path.append(os.path.join(this_file_path, '..'))
import stuff.mainfile
实际上 none 您的示例应该开箱即用。
让我们稍微修改一下bin/script.py
:
#! /usr/bin/env python
import sys
print sys.path
from stuff import mainfile
这应该会产生类似于
的结果['.../project/bin', ...]
Traceback (most recent call last):
File "bin/script.py", line 6, in <module>
from stuff import mainfile
ImportError: No module named stuff
只有the directory of the script(不是当前目录)自动添加到sys.path
:
As initialized upon program startup, the first item of this list,
path[0]
, is the directory containing the script that was used to invoke the Python interpreter.* If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input),path[0]
is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result ofPYTHONPATH
.
因此 sys.path
上没有 stuff
模块。我不确定您的环境设置,但这是没有设置其他参数时的规范结果(例如 PYTHONPATH
)。
同样,
from ..stuff import mainfile
会产生经典ValueError: Attempted relative import in non-package
。您被告知您只能相对于实际模块进行相对导入。由于内部 script
..
不引用模块(因为脚本本身可以说是顶级模块),相对导入在这里不起作用。从 Python 的角度来说,脚本之上没有模块,因此 ..
在脚本的上下文中使用时不指代有形的东西。
请注意,这也意味着它 不 有助于仅通过删除 __init__.py
标记将 project
和 project/bin
放入模块本身文件。相对导入到脚本的 parent 只有当脚本的父级实际上是 python 有一个概念的东西时才有可能。
这就是 -m
命令行开关存在的原因之一,使得从命令行 运行 模块成为可能。例如,给定上面的相对 import
python -m project.bin.script
可以解决问题,但前提是从正确的目录 (projectdir/..) 执行。
这个问题更严重from project.stuff import mainfile
因为 project
目录仅在您从 project
上面的目录启动脚本时自动位于 sys.path
和 不指定运行:
cd <projectdir>/..
python -m project.bin.script
# works
cd <projectdir>
python -m bin.script
# does not work, because `sys.path` starts with <projectdir>
# and it's `stuff.mainfile` now, not `project.stuff.mainfile`.
如果您想在脚本中从 project
导入模块,请根据您的需要修正 sys.path
:
import sys
import os
sys.path.insert(0, os.path.dirname(sys.path[0]))
from stuff import mainfile