python 在子目录中运行脚本时从上一级目录导入模块

o75abkj4  于 2023-02-11  发布在  Python
关注(0)|答案(3)|浏览(123)

假设我有一个脚本集合,为方便起见,它被组织在如下目录结构中:

root
│   helpers.py
│
├───dir_a
│       data.txt
│       foo.py
│
└───dir_b
        data.txt
        bar.py

foo.pybar.py是做不同事情的脚本,但是它们加载不同data.txt的方式是相同的,为了避免重复,我希望在helpers.py中放置一个load_data()函数,当运行子目录dir_adir_b中的脚本时可以导入该函数。
我尝试过在**dir_a/foo.py**中使用如下相对导入来导入helper:

from ..helpers import load_data

foo_data = load_data('data.txt')

# ...rest of code...

但是直接将**foo.py**作为脚本运行会在第1行失败,并显示ImportError

Traceback (most recent call last):
  File "path/to/file/foo.py", line 1, in <module>
    from ..helpers import load_data
ImportError: attempted relative import with no known parent package

我所尝试的精神在python中是否可行(即简单且无需修改sys.path)?来自 * 案例3:从Parent Directory * on this site导入,答案似乎是否定的,我需要重新构造我的脚本集合,以避免向上导入一个级别。
附加问题:如果不可能,理由是什么?

vwkv1x7d

vwkv1x7d1#

如果你在根目录下创建一个空的__init__.py(这会把根目录变成一个包),然后像这样调用你的foo.py脚本:
python -m root.dir_a.foo
我认为,只要您从“root”上面调用它,它就应该工作。我刚刚在我的计算机上尝试了类似的操作,它工作正常。
或者,因为您现在已经将'root'设置为包,所以您可以:
from root import helpers
当然,我假设你的根目录实际上并不叫'root',在这种情况下你应该适当地修改它。我还假设你使用的是Python3 --它在Python 2.7中不起作用。
至于为什么不把root作为一个包就不可能做到这一点,我认为这个想法是你的代码应该是位置不可知的。换句话说,你不应该依赖于你的foo.py知道它在系统中的位置。我不是Maven,但实际上可能foo.py * 不 * 知道这一点,在这种情况下,它没有办法解析../helpers

holgip5t

holgip5t2#

运行python脚本的正确方法是从根包的父目录运行,正如@JoeTodd在answer中建议的那样。如果直接从它的位置运行脚本,那么它无法知道它在一个包中,因此会出现错误(no known parent package)。
现在对于data.txt,python在给出一个相对路径时必须将其解析为一个绝对路径--它不能打开'data.txt',它需要打开c:/path/to/data.txt。因此相对路径连接到当前工作目录,默认情况下,该目录是脚本运行的目录(它也被添加到sys.path中,因此其中的包被解析)。因此,当您从root的父目录运行时,python会查找不存在的c:/.../parent dir of root/data.txt。正确的解决方案是 * 不 * 使用相对路径--所以:

path_to_data = os.path.join(os.path.dirname(__file__), 'data.txt'))
foo_data = load_data(path_to_data)
zi8p0yeb

zi8p0yeb3#

将以下行添加到www.example.com脚本的顶部foo.py,

import sys
sys.path.append('../root')

这将设置一个更高级别的模块的路径。然后,您将能够在www.example.com脚本中执行导入foo.py,如下所示:

from helpers import load_data

我被一个非常相似的问题卡住了,发现这是解决这个问题的最简单的方法

相关问题