导入路径 - 正确的方法?

时间:2011-06-24 08:54:59

标签: python path python-import

我知道有很多相似或相同的问题,但我仍然无法理解/找到适合我使用模块的正确方法。 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目录,其内容为..。但它不起作用 - 我猜它是用于别的东西。

结论:

  1. 始终使用绝对导入:import package1.module1

  2. 将引导程序添加到根文件夹以将某些模块作为独立脚本启动。这解决了从IDE运行脚本并且是一种pythonic方法。

  3. 2007年4月22日,Brett Cannon写道:

      

    此PEP将if __name__ == "__main__": ...成语更改为   if __name__ == sys.main: ...这样你至少有机会   在使用相对导入的包中执行模块。

         

    让这个PEP超越python-ideas。也停止了那里的讨论   正在提出许多新想法。 =)我列出了所有这些内容   拒绝的想法部分,虽然如果压倒性的支持一个   PEP可以转移到其中一个。

    我在这个以及__main__提出的任何其他提议中都是-1 机械。唯一的用例似乎是运行脚本 住在模块的目录中,我一直认为这是一个目录 反模式。为了让我改变主意,你必须让我相信 它不是。

    - Guido van Rossum

3 个答案:

答案 0 :(得分:26)

您的计划的切入点是什么?通常,程序的入口点将位于项目的根目录中。由于它位于根目录,因此根目录中的所有模块都是可导入的,只要其中包含__init__.py文件。

所以,使用你的例子:

my_project/
    main.py
    package1/
        __init__.py
        module1
        module2
    package2/
        __init__.py
        module1
        module2

main.py将是您的计划的切入点。由于作为main执行的文件会自动放在PYTHONPATH上,因此可以从顶级导入中获取package1package2

# 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

要带走的主要事情是,模块应该将自己置于路径上。路径应由进入程序的入口点自动确定,或由知道所有相关模块所​​在位置的安装脚本明确定义。

答案 1 :(得分:5)

我通常将每个包创建为可安装包(即创建一个setup.py文件),然后使用pip将它们安装到virtualenv中,仅用于此项目。

如果仍在开发中,您甚至可以安装使用pip -e。

答案 2 :(得分:0)

我已经迟到了5年......但是只做export PYTHONPATH=/path1:/path2:(注意尾随":") - 这样你的工作目录(从中运行python)将是在路上。