war*_*iuc 27 python path python-import
我知道有很多相似或相同的问题,但我仍然无法理解/找到适合我使用模块的正确方法.Python是我最喜欢的语言,我喜欢其中的一切,除了使用导入:递归导入(当你尝试引用一个尚未存在的名称时),导入路径等.
所以,我有这种项目结构:
my_project/
package1/
__init__.py
module1
module2
package2/
__init__.py
module1
module2
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
对我来说,这是有效的,但我觉得这不是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.当提出太多新想法时,停止了那里的讨论.=)我已经在Rejected Ideas部分中列出了所有这些内容,但是如果对一个人的压倒性支持出现,PEP可以转移到其中一个.
我在这个以及任何其他提议的__main__
机械装置上都是-1 .唯一的用例似乎是运行脚本,这些脚本恰好位于模块的目录中,我一直将其视为反模式.为了让我改变主意,你必须让我相信它不是.
Jos*_*ton 26
您的计划的切入点是什么?通常,程序的入口点将位于项目的根目录中.由于它位于根目录,因此根目录中的所有模块都是可导入的,只要其中包含__init__.py文件即可.
所以,使用你的例子:
my_project/
main.py
package1/
__init__.py
module1
module2
package2/
__init__.py
module1
module2
Run Code Online (Sandbox Code Playgroud)
main.py将是您的计划的切入点.因为作为主要执行的文件会被自动的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 *
Run Code Online (Sandbox Code Playgroud)
请注意,在上面,package1和package2相互依赖.绝不应该这样.但这只是能够从任何地方导入的一个例子.
main.py也不必是任何花哨的东西.它可以很简单:
# main.py
if __name__ == '__main__':
from package1.module1 import SomeClass
SomeClass().start()
Run Code Online (Sandbox Code Playgroud)
我想说的是,如果一个模块需要其他模块可以访问,那么该模块应该可以作为顶级导入使用.模块不应该尝试将自己作为顶级导入(直接在PYTHONPATH上).
如果模块直接包含在项目中,则应确保所有进口都能得到满足,这应该是项目的责任.有两种方法可以做到这一点.第一种方法是创建一个bootstrapper文件,例如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
Run Code Online (Sandbox Code Playgroud)
要带走的主要事情是,模块不应该放在路径上.路径应由进入程序的入口点自动确定,或由知道所有相关模块所在位置的安装脚本明确定义.
我通常将每个包创建为可安装的包(即创建一个setup.py文件),然后使用pip将它们安装到virtualenv中,仅用于此项目.
如果仍在开发中,您甚至可以安装使用pip -e.