我有一个像这样组织的简单应用程序:
.
`-- app
|-- __init__.py (empty)
|-- extensions.py (just defines foo())
`-- server.py
和server.py看起来像这样:
from app.extensions import foo
将此作为python app/server.py
运行当然不起作用,因为server.py不是"在" 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;像这样的包导入系统?
答案 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]