如何在包里面引用Python中的顶级模块?

时间:2012-01-02 23:16:44

标签: python module packages

在下面的层次结构中,是否有一种方便且通用的方法可以在下面的所有.py文件中使用通用术语引用top_package?我想有一个一致的方法来导入其他模块,所以即使“top_package”更改名称也没有任何中断。

我不赞成使用像“..level_one_a”这样的相对导入,因为相对路径将与下面的每个python文件不同。我正在寻找一种方式:

  1. 每个python文件可以对包中的同一个模块使用相同的import语句。
  2. 在包内的任何.py文件中对“top_package”的解耦引用,因此无论名称“top_package”如何变化,都不会中断。

    top_package/
      __init__.py
      level_one_a/
        __init__.py
        my_lib.py
        level_two/
          __init__.py
          hello_world.py
      level_one_b/
        __init__.py
        my_lib.py
      main.py
    

5 个答案:

答案 0 :(得分:13)

这应该做的工作:

top_package = __import__(__name__.split('.')[0])

这里的技巧是,对于每个模块,__name__变量包含以点分隔的模块的完整路径,例如top_package.level_one_a.my_lib。因此,如果您想获得顶级包名称,只需获取路径的第一个组件并使用__import__导入它。

尽管用于访问包的变量名称仍称为top_package,但您可以重命名该包,如果仍然有效。

答案 1 :(得分:7)

将您的包和main脚本放入外部容器目录中,如下所示:

container/
    main.py
    top_package/
        __init__.py
        level_one_a/
            __init__.py
            my_lib.py
            level_two/
                __init__.py
                hello_world.py
        level_one_b/
            __init__.py
            my_lib.py

运行main.py时,其父目录(container)将自动添加到sys.path的开头。由于top_package现在位于同一目录中,因此可以从包树中的任何位置导入它。

因此hello_world.py可以像这样导入level_one_b/my_lib.py

from top_package.level_one_b import my_lib

无论容器目录的名称是什么,或者它位于何处,导入都将始终适用于此安排。

但请注意,在您的原始示例top_package中,它可以轻松地充当容器目录本身。您所要做的就是删除top_package/__init__.py,您将完全保留相同的安排。

之前的import语句将更改为:

from level_one_b import my_lib

您可以随意重命名top_package

答案 2 :(得分:1)

您可以结合使用__import__()函数和包的__path__属性。

例如,假设您希望从包中的其他位置导入<whatever>.level_one_a.level_two.hello_world。你可以这样做:

import os
_temp = __import__(__path__[0].split(os.sep)[0] + ".level_one_a.level_two.hello_world")
my_hello_world = _temp.level_one_a.level_two.hello_world

此代码独立于顶级包的名称,可以在包中的任何位置使用。它也很难看。

答案 3 :(得分:0)

我认为如果不使用相对导入或命名包,#2是不可能的。您必须通过显式调用其名称或使用相对导入来指定要导入的模块。否则翻译会怎么知道你想要什么?

如果您将应用程序启动器设置为高于top_level/一级并使其import top_leve升,则可以从top_level包中的任何位置引用top_level.*

(我可以向您展示我正在处理的软件示例:http://github.com/toddself/beerlog/

答案 4 :(得分:0)

这适用于库模块:

import __main__ as main_package
TOP_PACKAGE = main_package.__package__.split('.')[0]