导入路径-正确的方法?
我知道有很多类似或相同的问题,但是我仍然无法理解/找到正确的方法来使用模块。Python是我最喜欢的语言,除使用导入外,我喜欢其中的所有内容:递归导入(当您尝试引用尚不存在的名称时),导入路径等。
因此,我有这种项目结构:
my_project/
package1/
__init__.py
module1
module2
package2/
__init__.py
module1
module2
Package1
可以用作独立单位,但也应由导入package2
。我现在在做什么,例如,在package1.module1
我编写中from
package1 import module2
,即使用导入模块的完整路径。我这样做是因为,如果我使用import
module2
-当从另一个包(package2
)中导入该模块时,它将不起作用。我也无法使用from . import
module2
-module1
直接运行时将无法使用。
好的,因此要from package1 import
module2
在package1.module1
两种情况下都可以工作(直接运行时package1.module1
和从中导入时package2
),请在以下代码的开头添加这些行package1.module1
:
import os, sys
currDir = os.path.dirname(os.path.realpath(__file__))
rootDir = os.path.abspath(os.path.join(currDir, '..'))
if rootDir not in sys.path: # add parent dir to paths
sys.path.append(rootDir)
对我来说这可行,但是我觉得这不是pythonic。难道我做错了什么?
我是否应该始终package1.module1
从项目根目录运行?如果是这样,这将使从IDE运行它变得不便-我需要以某种方式在其中设置路径。
更新:我试图将一个文件添加root.pth
到package1
dir中,其内容为..
。但这是行不通的-我想这是为其他目的。
结论:
-
始终使用绝对导入:
import package1.module1
-
将引导程序添加到根文件夹以启动某些模块作为独立脚本。这解决了从IDE运行脚本的问题,这是一种pythonic方法。
2007年4月22日,布雷特·坎农(Brett Cannon)写道:
此PEP会将
if __name__ == "__main__": ...
习惯用法更改为,if __name__ == sys.main: ...
以便您至少有机会在使用相对导入的程序包中执行模块。使这个PEP越过python-
ideas。当提出太多新想法时,就停止了讨论。=)我已经在“被拒绝的想法”部分列出了所有这些人,尽管如果对一个人的压倒性支持出现,PEP可能会转移到其中之一。
我对此表示怀疑,也对任何其他提议的__main__
机械装置都为-1
。唯一的用例似乎是正在运行的脚本,它们恰好位于模块目录中,我一直将其视为反模式。为了让我改变主意,您必须说服我不要。
-
您的程序的切入点是什么?通常,程序的入口点将位于项目的根目录。由于它位于根目录下,因此如果根目录内的所有
__init__.py
文件都可以导入,则可以导入该模块。因此,使用您的示例:
my_project/ main.py package1/ __init__.py module1 module2 package2/ __init__.py module1 module2
main.py
将是您程序的入口点。因为作为main执行的文件会自动放在PYTHONPATH上,所以package1
和package2
都可以从顶级导入中获得。# in main.py from package1.module1 import * from package1.module2 import * # in package1.module1 import module2 from package2.module1 import * # in package2.module1 import * import module2 from package1.module1 import *
注意,在上面,package1和package2相互依赖。永远都不会这样。但这只是能够从任何地方导入的示例。
main.py
也不必花哨。可以很简单:# main.py if __name__ == '__main__': from package1.module1 import SomeClass SomeClass().start()
我要说明的一点是,如果一个模块需要其他模块可以访问,则该模块应该可以作为顶级导入使用。模块不应尝试将自身作为顶级导入(直接在PYTHONPATH上)。
如果模块直接包含在项目中,则应确保所有进口货均能得到满足,这是 项目
的责任。有两种方法可以做到这一点。第一种是通过main.py
在项目文件夹中创建一个引导程序文件。另一种方法是通过创建一个将所有相关路径添加到PYTHONPATH的文件,该文件由可能存在的任何入口点加载。例如:
# setup.py import sys def load(): paths = ['/path1/','/path2/','/path3/'] for p in path: sys.path.insert(0, p) # entrypoint.py from setup import load load() # continue with program
要带走的主要内容是, 不应 将模块放置在路径上。路径应由程序的入口点自动确定,或由知道所有相关模块在哪里的安装脚本明确定义。