如何让python包导入工作在main?

时间:2018-06-18 15:07:37

标签: python python-import python-module

我有一个像这样组织的简单应用程序:

.
`-- app
    |-- __init__.py (empty)
    |-- extensions.py (just defines foo())
    `-- server.py

和server.py看起来像这样:

from app.extensions import foo

将此作为python app/server.py运行当然不起作用,因为server.py不是&#34;在&#34; app从命令行运行时。其包名为__main__。我知道将其作为python -m app.server运行,但出于各种原因我不能这样做(其中,我使用了重新加载器,python -m<foo>&#34;帮助&#34 ;使用完整的模块名称重写argv。

我想我理解非常依赖拜占庭式的Python包/模块导入内容,至少我已经阅读了很多内容。我认为解决这个问题的标准(?)方法是将app目录添加到sys.path,类似于sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))。但这对我来说似乎很奇怪,并且正确地做到这一点非常重要(参见关于这个主题的其他类似的SO问题)。似乎应该有一些方法可以通过设置__name__和/或__package____path__或更多其他内容告诉python&#34;这是app.server&#34;隐藏。

有没有办法去傻瓜&#34;像这样的包导入系统?

1 个答案:

答案 0 :(得分:1)

不要去那里,没有必要开始使用Python包结构。最好的方法是不将脚本放在包中

在软件包外部有一个单独的server.py文件 ,并让它导入app.server或其他模块来完成其工作。这可以很简单:

import sys
from app.server import main

sys.exit(main(sys.argv[1:]))

除此之外,python -m可能已更新sys.argv[0]以指向完整文件名(它在执行的模块中基本上等于__file__),但__spec__ module spec object包含原始包名。如果您必须使用python -m 并且,则需要使用__main__作为main属性运行的包的完整限定名称:

print(__spec__.name)

因此对于package.main模块,上面会打印package.main而不是__main__

$ mkdir package
$ touch package/__init__.py
$ echo 'if __name__ == "__main__": print("__spec__.name", __spec__.name)' > package/main.py
$ python3 -m package.main
package.main

因此,如果您的重新加载器要求sys.argv包含-m package.main,您可以使用以下代码更新sys.argv

import sys

sys.argv[:1] = ['-m', __spec__.name]