导入路径-正确的方法?

发布于 2021-01-29 18:26:30

我知道有很多类似或相同的问题,但是我仍然无法理解/找到正确的方法来使用模块。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 module2package1.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.pthpackage1dir中,其内容为..。但这是行不通的-我想这是为其他目的。

结论:

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

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

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

此PEP会将if __name__ == "__main__": ...习惯用法更改为, if __name__ == sys.main: ... 以便您至少有机会在使用相对导入的程序包中执行模块。

使这个PEP越过python-
ideas。当提出太多新想法时,就停止了讨论。=)我已经在“被拒绝的想法”部分列出了所有这些人,尽管如果对一个人的压倒性支持出现,PEP可能会转移到其中之一。

我对此表示怀疑,也对任何其他提议的__main__ 机械装置都为-1
。唯一的用例似乎是正在运行的脚本,它们恰好位于模块目录中,我一直将其视为反模式。为了让我改变主意,您必须说服我不要。

-吉多·范罗苏姆

关注者
0
被浏览
51
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    您的程序的切入点是什么?通常,程序的入口点将位于项目的根目录。由于它位于根目录下,因此如果根目录内的所有__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
    

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



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看