导入路径 - 正确的方法? [英] Import paths - the right way?

查看:29
本文介绍了导入路径 - 正确的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道有很多类似或相同的问题,但我仍然无法理解/找到适合我使用模块的正确方法.Python 是我最喜欢的语言,除了使用导入之外,我喜欢其中的所有内容:递归导入(当您尝试引用尚不存在的名称时)、导入路径等.

I know there are A LOT of similar or the same questions, but i still cannot understand / find the right way for me to work with modules. Python is my favorite language, and i like everything in it except working with imports: recursive imports (when you try to reference a name that is not yet there), import paths, etc.

所以,我有这样的项目结构:

So, I have this kind of a project structure:

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 may be used a standalone unit, but is also expected to be imported by package2. What am i doing now, is that, for example, in package1.module1 i write from package1 import module2, i.e. using full path to imported module. I do this because if i use import module2 -- this will not work when the module will be imported from another package (package2). I also cannot use from . import module2 -- this will not work when running module1 directly.

好的,所以对于 package1.module1 中的 from package1 import module2 在这两种情况下都可以工作(直接运行 package1.module1 和当从 package2 导入)我在 package1.module1 的开头添加这些行:

OK, so for from package1 import module2 in package1.module1 to work in both cases (when running directly package1.module1 and when importing it from package2) i add these lines at the beginning of 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.我做错了什么吗?

For me this works, but i feel this is not pythonic. Am i doing something wrong?

相反,我应该始终从项目根目录运行 package1.module1 吗?如果是这样,这会使从 IDE 运行它变得不方便——我需要以某种方式在其中设置路径.

Should i, instead, always run package1.module1 from project root? If so, this makes inconvenient to run it from an IDE -- i need somehow to set paths in it.

更新:我尝试添加一个文件 root.pthpackage1 目录,内容为 ...但它没有用——我猜它是为了别的东西.

UPDATE: I tried to add a file root.pth to package1 dir with contents of ... But it didn't work -- i guess it's intended for something else.

结论:

  1. 总是使用绝对导入:import package1.module1

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

Add a bootstrapper to the root folder to start some of the modules as a standalone script. This solves running the script form an IDE and is a pythonic approach.

在 4/22/07,布雷特·坎农写道:

On 4/22/07, Brett Cannon wrote:

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

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.

通过 python-ideas 运行这个 PEP.也停止了讨论人们提出了许多新想法.=) 我已经列出了所有这些被拒绝的想法部分,尽管如果对一个想法提供压倒性的支持出现 PEP 可以转移到其中之一.

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机械.唯一的用例似乎是运行发生的脚本住在一个模块的目录中,我一直认为它是一个反模式.为了让我改变主意,你必须说服我不是.

I'm -1 on this and on any other proposed twiddlings of the __main__ machinery. The only use case seems to be running scripts that happen to be living inside a module's directory, which I've always seen as an antipattern. To make me change my mind you'd have to convince me that it isn't.

--Guido van Rossum

推荐答案

您的程序的入口点是什么?通常,程序的入口点位于项目的根部.由于它位于根目录中,因此根目录中的所有模块都是可导入的,前提是它们中有一个 __init__.py 文件.

What is the entry point for your program? Usually the entry point for a program will be at the root of the project. Since it is at the root, all the modules within the root will be importable, provided there is an __init__.py file in them.

因此,使用您的示例:

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

main.py 将是您程序的入口点.因为作为 main 执行的文件会自动放在 PYTHONPATH 中,package1package2 都可以从顶级导入中获得.

main.py would be the entry point for your program. Because the file that is executed as main is automatically put on the PYTHONPATH, both package1 and package2 are available from the top level import.

# 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是相互依赖的.情况绝不应该如此.但这只是能够从任何地方导入的示例.

Note that in the above, package1 and package2 depend on each other. That should never be the case. But this is just an example of being able to import from anywhere.

main.py 也不必太花哨.可以很简单:

main.py doesn't have to be anything fancy either. It can be very simple:

# main.py

if __name__ == '__main__':
    from package1.module1 import SomeClass
    SomeClass().start()

我想说明的一点是,如果一个模块需要被其他模块访问,那么该模块应该作为顶级导入可用.模块不应尝试将自身作为顶级导入(直接在 PYTHONPATH 上).

The point I'm trying to make, is that if a module needs to be accessible by other modules, that module should be available as a top level import. A module should not attempt to put itself as a top level import (directly on the PYTHONPATH).

项目应该负责确保如果模块直接包含在项目中,所有导入都可以得到满足.有两种方法可以做到这一点.第一种方法是在项目文件夹中创建一个引导程序文件,例如 main.py.另一种方法是创建一个文件,将所有相关路径添加到 PYTHONPATH,该文件由可能存在的任何入口点加载.

It should be the responsibility of the project for ensuring that all imports can be satisfied if the module is included directly in the project. There are two ways to do this. The first is by creating a bootstrapper file such as main.py in the project folder. The other, is by creating a file that adds all relevant paths to PYTHONPATH, that is loaded by any entry points that may exist.

例如:

# 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

要带走的主要内容是,模块应该将自己置于路径上.路径应该由程序的入口点自动确定,或者由知道所有相关模块在哪里的安装脚本明确定义.

The main thing to take away, is that a module is not supposed to put itself on the path. The path should be determined automatically by the entry point into the program, or defined explicitly by a setup script that knows where all the relevant modules are.

这篇关于导入路径 - 正确的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆