Python3-导入系统和相对导入概念



我对Python相当陌生,特别是Python3;在这里学习诀窍。

问题摘要:可以概括为不完全理解导入系统在Python中的工作方式以及什么是相对导入,尽管我会提到我实际理解的内容,如果这里有任何误解,请纠正我。

我的理解:Python的行为不同;文件.py";使用python file.py从REPL运行,而使用import file.py导入此文件,此行为与__name__变量的值分配不同;在第一种情况下给定值CCD_ 4,在第二种情况下给出值__file__。导入模块后;python不会保存获取它所遵循的层次结构,因此,如果在之前导入的模块的同一级别中需要导入模块,那么仍然需要一个完全限定的名称。


上下文:

考虑以下目录

Main:
|______ main.py
|
|______ PackageOne:
|
|______ ______ __init__.py
|
|______ ______ ModuleOne.py
|
|______ ______ PackageTwo:
|
|______ ______ ______ __init__.py
|
|______ ______ ______ ModuleTwo.py

结构详细信息:

  • main.py=>程序条目("通过IDE运行的第一个文件")。

  • CCD_ 7=>包含__init__.py初始值设定项的包文件夹以及CCD_ 9模块。

    • __init__.py=>导入ModuleOne.py模块的PackageOne的初始化python文件和PackageTwo
    • ModuleOne.py是一个模块python文件,其中包含一个名为FuncOne()的函数
  • CCD_ 15=>包含__init__.py初始值设定项的包文件夹以及CCD_ 17模块。

    • __init__.py=>导入ModuleTwo.py模块的PackageTwo的初始化python文件
    • ModuleTwo.py一个模块python文件,包含一个名为FuncTwo()的函数文件内容:

      main.py:

    导入PackageOnePackageOne/__init__

    print(f"来自ParentPackage,名称:{名称}")导入PackageTwo,ModuleOne

PackageOne/ModuleOne:

def FuncOne():
print(__name__)

第二包/__init__

print(f"From ParentPackage, Name:{__name__}")
import ModuleTwo

包二/模块二

def FuncTwo():
print(__name__)

详细问题:

  • A):的输出

没有名为"PackageTwo"的模块

弹出。从导入中删除PackageTwo后,ModuleOne也会发生同样的情况。

  • B):在重构文件代码时,如下所示:

    PackageOne/__init__

    print(f"From ParentPackage, Name:{__name__}")
    from PackageOne import PackageTwo, ModuleOne
    

    第二包/__init__

    print(f"From ParentPackage, Name:{__name__}")
    from PackageOne.PackageTwo import ModuleTwo
    

运行main.py不会引起任何问题;来自ParentPackage,名称:PackageOne";以及";来自ChildPackage的名称:PackageOne.PackageTwo";,但是尝试执行CCD_ 23文件中的任何一个直接输出的错误

没有命名的模块:"PackageOne">

这似乎与模块化概念背道而驰,模块化概念将代码划分为小部分以实现可重用性/可读性,但实际上无法从编写代码的同一范围运行代码,或者从不同范围导入代码的灵活性。虽然我立刻想到也许相对重要性可能会帮助解决这个问题?但我对相对重要性的理解似乎并不具体,所以复习一下这个话题会很有帮助。

谢谢!

我已经找到了解决这个问题的方法,但这不是一个好方法,因为它增加了依赖关系之间的耦合。

if __name__ != "__main__":
import importlib
my_module = importlib.import_module(f'{__name__}.ModuleOne')
else:
import ModuleOne

importlib.import_module(f'{__name__}.ModuleOne')是一个导入模块的函数,通过提供导入关键字__name__的路径/调用方,我可以从任何范围导入ModuleOne

这将被放置在PackageOne __init__.py中,通过这样做,我可以很容易地直接或通过导入来运行__init__.py文件,但通过在导入函数中显式键入ModuleOne的字符串表示,就不可能在更改依赖项名称时自动重构。这个答案是为了引导自己朝着事情如何运作的方向前进,也许还能找到更好的方法。

我想我终于明白了,有几个信息缺失,如果我错了,请纠正我。

  1. __a__导入__b__可以在两个上下文中:

    • 脚本文件:这里的__a__只能是模块或子目录的名称,而__b__可以是要插入的模块的属性。这就引出了一个问题,如果python文件作为脚本运行,如何从不同的目录导入模块?我们开始使用sys.path.append("directory path needed")将目录添加到python搜索的目录列表中,当然在此之前导入sys

    • Module:Module意味着这个python文件将被导入另一个模块或直接导入正在运行的脚本文件,因此__a__部分可以是sys.path中存在的目录中的模块名称,也可以是目录;例如CCD_ 38注意:重要的是要知道,当使用绝对路径时,启动从根包到所需包或模块的目录路径非常重要。相反,可以使用相对路径。

    • 结论:由于将python文件作为脚本运行,__name__在评估为'__main__'0时,无法使用from关键字遍历到其他路径。

  2. __init__.py文件并不意味着要作为脚本运行,因此它们有时包括使用from directory键盘导入模块或其他包。

  3. 以上两点的相关性,from . import package这样的相对导入只对模块和包的__init__.py有效,包本身是模块而不是脚本。

  4. 兄弟包不需要更改目录即可相互访问。


摘要

在处理模块时,可以使用from directoryfrom . (relative paths),但在处理脚本时,如果需要来自不同目录的特定模块,则使用sys.path.append("directory")将其添加到路径中,最后包的__init__.py是模块,而不是脚本。(如果需要作为脚本/模块工作,则需要if条件if __name__ != __main__: relative import或其他变通方法)。

最新更新