导入路径-正确的路径?

2024-06-09 05:07:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道有很多类似或相同的问题,但我仍然无法理解/找到适合我使用模块的正确方法。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时不起作用。

好的,为了使package1.module1中的from package1 import module2在这两种情况下都能工作(当直接运行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)

对我来说这很有效,但我觉得这不是Python。我做错什么了吗?

相反,我是否应该始终从项目根目录运行package1.module1?如果是这样,从IDE运行它会很不方便——我需要在其中设置路径。

更新:我试图向root.pth目录添加一个内容为..的文件root.pth。但它不起作用——我想它是为了别的目的。

结论:

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

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

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

This PEP is to change the if __name__ == "__main__": ... idiom to if __name__ == sys.main: ... so that you at least have a chance to execute module in a package that use relative imports.

Ran this PEP past python-ideas. Stopped the discussion there when too many new ideas were being proposed. =) I have listed all of them in the Rejected Ideas section, although if overwhelming support for one comes forward the PEP can shift to one of them.

我对这件事和任何其他关于__main__的提议都是-1 机械。唯一的用例似乎是运行发生的脚本 住在一个模块的目录中,我一直认为 反模式。为了让我改变主意你得说服我 不是的

--Guido van Rossum


Tags: 模块thetopathfromimport路径if
3条回答

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

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

你的程序的入口点是什么?通常,程序的入口点将位于项目的根目录。因为它在根目录下,根目录下的所有模块都是可导入的,只要其中有一个__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

最重要的是,一个模块是而不是应该让自己走上正轨。路径应该由程序的入口点自动确定,或者由知道所有相关模块在哪里的安装脚本显式定义。

我在这里迟到了5年。。但是只要做export PYTHONPATH=/path1:/path2:(注意尾随的“)——这样您的工作目录(运行python的目录)就会在路径中。

相关问题 更多 >