我有以下目录结构:
some-tools-dir/
base_utils.py
other_utils.py
some-tool.py
some-other-tool.py
some-other-tools-dir/
basetools -> symlink to ../some-tools-dir
yet-another-tool.py
在other_utils.py
中,我有:
import base_utils
现在,在yet-another-tool.py
,我想这样做:
import basetools.other_utils
这不起作用,因为Python不会将basetools
识别为Python包。
所以我添加一个空的basetools/__init__.py
。
现在,在other_utils
中,我得到了例外:
import base_utils
ImportError: No module named base_utils
所以我将该行更改为:
from . import base_utils
而且yet-another-tool.py
现在有效。
但是,some-tool.py
不再有效。它导入other_utils
,然后我得到例外:
from . import base_utils
ValueError: Attempted relative import in non-package
现在,我可以将此黑客/解决方法添加到some-tools-dir/*-tool.py
:
import os, sys
__package__ = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
sys.path += [os.path.dirname(os.path.dirname(os.path.abspath(__file__)))]
__import__(__package__)
此外,将所有本地导入相对于这些文件。
我猜这解决了这个问题。但是,它看起来有点非常难看,我必须修改sys.path
。我尝试了这种黑客的几种变体,但是,如果可能的话,我想支持多个Python版本,因此使用模块importlib
变得复杂,尤其是。因为我有Python 3.2,我不喜欢使用模块imp
,因为它已被弃用。而且,它似乎变得更加复杂。
有什么我想念的吗?对于一个似乎并不太常见的用例来说,这一切看起来都很丑陋而且太复杂了(对我来说)。我的黑客有更清洁/更简单的版本吗?
我愿意做的限制是只支持Python> = 3.2,如果这简化了任何事情。
答案 0 :(得分:1)
(请注意,此答案是通过拼凑来自this answer和this question的信息构建的,因此如果您愿意,可以将其投票给他们。
这看起来不那么黑,至少可以使用Python 2.7 +:
if __name__ == "__main__" and __package__ is None:
import sys, os.path as path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
from some_tools_dir import other_utils
我认为你发现这个困难的主要原因是因为在python包中包含可执行脚本实际上并不常见。 Guido van Rossum实际上称之为"antipattern"。通常,您的可执行文件位于包的根目录之上,然后只需使用:
from some_tools_dir import other_utils
没有任何大惊小怪。
或者,如果你想执行一个包含在包中的脚本,你实际上将它称为包的一部分(再次,从包的父目录):
python -m some_tools_dir.other_utils
答案 1 :(得分:0)
您是否可以将最高根路径添加到PYTHONPATH?
如果是,您可以添加
__init__.py
将文件存入some-tools-dir(和/或其他工具-dir)
然后从other_utils.py开始
from some-tools-dir import base_utils
在yet-another-tool.py中你做了
from some-tools-dir import other_utils
然后,您可以删除符号链接,并具有正确的命名空间。