这里有几个选项。
您最好的选择是将包与使用该包的脚本分开。查看entry_points 的设置工具。您将 setuptools 指向包中的一个函数,它会创建一个脚本来调用它。漂亮...
在解决这个问题时,我设置了以下包结构:
test_dir
+ __init__.py
+ main.py
+ sub1
--+ __init__.py
--+ script.py
+ sub2
--+ __init__.py
--+ module.py
我已确保可以通过 PYTHONPATH 访问 test_dir。
脚本都超级简单(只是打印一些东西):
# main.py
def func_in_main():
print("Hello from main.py!")
# module.py
def run_func():
print("Hello from script in sub2.py!")
# script.py
from ..sub2 import module
from .. import main
def entry_point():
module.run_func()
main.func_in_main()
if __name__ == '__main__':
entry_point()
现在,如果我尝试直接运行它会发生什么?
$ python test_package/test_dir/sub1/script.py
Traceback (most recent call last):
File "test_package/test_dir/sub1/script.py", line 2, in <module>
from ..sub2 import module
ValueError: Attempted relative import in non-package
嗯......真是太糟糕了(这就是我试图在你原来的问题的 cmets 中描述的情况)。顺便说一句,无论我当前的工作目录如何,都会发生这种情况......但是,我可以在我的文件系统上的任何地方使用-m标志运行它1:
$ python -m test_dir.sub1.script
Hello from script in sub2.py!
Hello from main.py!
万岁!我们只需要指定模块路径,然后我们就可以了(请记住,test_dir 必须可以通过您的 PYTHONPATH 访问才能正常工作)。好的,但是如果我们真的想调用脚本而不是使用模块路径怎么办?如果是这种情况,我们可以在进行任何导入之前修改 __package__ 变量:
# script.py (updated)
if __name__ == '__main__' and __package__ is None:
__package__ = 'test_dir.sub1'
import test_dir # needed to suppress SystemError -- I'm not sure why...
from .. import main
from ..sub2 import module
def entry_point():
module.run_func()
main.func_in_main()
if __name__ == '__main__':
entry_point()
现在让我们尝试再次直接运行这个东西:
$ python test_package/test_dir/sub1/script.py
test_package/test_dir/sub1/script.py:4: RuntimeWarning: Parent module 'test_dir.sub1' not found while handling absolute import
import test_dir
Hello from script in sub2.py!
Hello from main.py!
我们仍然得到RuntimeWarning,但它运行正常。更多详情,请查看PEP-0366。
1一般来说,我已经从包外部运行了大部分这些(比test_dir 高一级),但是如果我从内部运行它,这些示例仍然有效 包也是如此。使用-m,您始终指定模块的完整路径(test_dir.sub1.script),没有它,您只需指定文件的相对或绝对路径)