在下面的层次结构中,是否有一种方便且通用的方法可以在下面的所有.py文件中使用通用术语引用top_package?我想有一个一致的方法来导入其他模块,所以即使“top_package”更改名称也没有任何中断。
我不赞成使用像“..level_one_a”这样的相对导入,因为相对路径将与下面的每个python文件不同。我正在寻找一种方式:
在包内的任何.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
答案 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]