代码之家  ›  专栏  ›  技术社区  ›  GaryO

如何使python包导入在main中工作?

  •  0
  • GaryO  · 技术社区  · 8 年前

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

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

    server.py如下所示:

    from app.extensions import foo
    

    运行此为 python app/server.py 当然不起作用,因为从命令行运行时server.py不在应用程序中。它的包名是 __main__ . 我知道它是 python -m app.server 可以,但是由于各种原因我不能这样做(其中,我使用了一个重载器,并且 python -m<foo> “helpfully”用完整的模块名重写argv)。

    我想我理解非常拜占庭式的python包/模块导入,至少我读了很多。我认为标准是?解决这个问题的方法是将app dir添加到sys.path,如下所示 sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) . 但这对我来说似乎很奇怪,而且正确地做是很重要的(参见其他类似的关于这个主题的so问题)。似乎应该有某种方法通过设置来告诉python“这是app.server” __name__ 和/或 __package__ __path__ 或者其他更隐蔽的东西。

    有没有办法像这样“愚弄”包裹进口系统?

    1 回复  |  直到 8 年前
        1
  •  1
  •   Martijn Pieters    8 年前

    不要这么做,没有必要开始研究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 对象包含原始包名。如果你必须使用 蟒蛇-M 需要有正在运行的包的完整限定名 __main__ 作为 main 属性:

    print(__spec__.name)
    

    因此,对于 package.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 ,您可以更新 阿尔病毒 用:

    import sys
    
    sys.argv[:1] = ['-m', __spec__.name]
    
    推荐文章