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

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

问题描述

我知道有很多类似或相同的问题,但是我仍然无法理解/找到正确的方法来使用模块. 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.pth添加到package1目录中,其内容为...但这没有用-我想它还可以用于其他用途.

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.

07年4月22日,布雷特·坎农(Brett Cannon)写道:

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.

将此PEP越过python-ideas.也停止了讨论 提出了许多新的想法. =)我都列出了所有这些 拒绝的想法"部分,尽管如果获得压倒性的支持, 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.

因此,以您的示例为例:

So, using your example:

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天全站免登陆