如何使 python 包导入在 main 中工作?
How to make python package imports work in main?
我有一个这样组织的简单应用程序:
.
`-- app
|-- __init__.py (empty)
|-- extensions.py (just defines foo())
`-- server.py
和 server.py 看起来像这样:
from app.extensions import foo
运行 这作为 python app/server.py
当然不起作用,因为当 运行 来自命令行时 server.py 不是 "in" 应用程序。它的包名是__main__
。我知道 运行 宁它作为 python -m app.server
工作,但由于各种原因我不能这样做(其中,我正在使用重新加载器,并且 python -m<foo>
"helpfully" 重写带有完整模块名称的 argv)。
我想我理解极其复杂的 Python package/module 导入内容,至少我已经阅读了很多。我认为解决这个问题的标准(?)方法是将应用程序目录添加到 sys.path,类似于 sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
。但这对我来说似乎很奇怪,而且正确地做起来很重要(请参阅有关此主题的其他类似的 SO 问题)。似乎应该有一些方法可以通过设置 __name__
and/or __package__
或 __path__
或其他更隐藏的东西来告诉 python "this is app.server" .
有什么方法可以"fool"这样的包导入系统吗?
不要去那里,没有必要开始研究 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 对象包含原始包名称。如果您必须使用 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]
我有一个这样组织的简单应用程序:
.
`-- app
|-- __init__.py (empty)
|-- extensions.py (just defines foo())
`-- server.py
和 server.py 看起来像这样:
from app.extensions import foo
运行 这作为 python app/server.py
当然不起作用,因为当 运行 来自命令行时 server.py 不是 "in" 应用程序。它的包名是__main__
。我知道 运行 宁它作为 python -m app.server
工作,但由于各种原因我不能这样做(其中,我正在使用重新加载器,并且 python -m<foo>
"helpfully" 重写带有完整模块名称的 argv)。
我想我理解极其复杂的 Python package/module 导入内容,至少我已经阅读了很多。我认为解决这个问题的标准(?)方法是将应用程序目录添加到 sys.path,类似于 sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
。但这对我来说似乎很奇怪,而且正确地做起来很重要(请参阅有关此主题的其他类似的 SO 问题)。似乎应该有一些方法可以通过设置 __name__
and/or __package__
或 __path__
或其他更隐藏的东西来告诉 python "this is app.server" .
有什么方法可以"fool"这样的包导入系统吗?
不要去那里,没有必要开始研究 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 对象包含原始包名称。如果您必须使用 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]