zoukankan      html  css  js  c++  java
  • Python3 中 的 绝对导入 与 相对导入

    背景:

    在学习tf的时候,看到了from __future__ import absolute_import,所以登记学习一下。

    概览:

    一般模块导入规则:
    import xxx 时搜索文件的优先级如下:

    1.在当前目录下搜索该模块
    2.在环境变量 PYTHONPATH 中指定的路径列表中依次搜索
    3.在 Python 安装路径的 lib 库中搜索
    
    
    在 Python 程序启动时进行配置,自动将 top-level file 的 home 目录(或用一个''表示当前工作目录)、PYTHONPATH 设置的目录、.pth 文件里的目录、标准库目录合并成一个 list ,组成每次 import 时 Python 搜索的目录列表,放到sys.path 中
    

    关于sys.path的有关调试

    • python2 版本
    ~ # python
    $ python
    Python 2.7.12 (default, Oct  8 2019, 14:14:10)
    [GCC 5.4.0 20160609] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.path
    ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
    
    • python3 版本
    $ python3
    Python 3.5.2 (default, Oct  8 2019, 13:06:37)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.path
    ['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
    

    Python import 的步骤:

    python 所有加载的模块信息都存放在 sys.modules 结构中,当 import 一个模块时,会按如下步骤来进行

    如果是 import A,检查 sys.modules 中是否已经有 A;如果有则不加载,如果没有则为 A 创建 module 对象,并加载 A
    如果是 from A import B,先为 A 创建 module 对象,再解析A,从中寻找B并填充到 A 的 dict

    Python中的绝对导入与相对导入:
    相对导入与绝对导入,这两个概念是相对于包内导入而言的。包内导入即是包内的模块导入包内部的模块。
    所谓的包,就是包含 init.py 文件的目录,该文件在包导入时会被首先执行,该文件可以为空,也可以在其中加入任意合法的 Python 代码。

    相对导入可以避免硬编码,对于包的维护是友好的。绝对导入可以避免与标准库命名的冲突,实际上也不推荐自定义模块与标准库命令相同。

    绝对导入:指明顶层 package 名。比如 import a,Python 会在 sys.path里寻找所有名为 a 的顶层模块。

    import A.B 
    
    或
    
    from A import B
    

    相对导入:在不指明 package 名的情况下导入自己这个 package 的模块,表示只在 package 的内部目录中搜索,并且不会搜索位于 sys.path 上某处同名的模块,直接效果就是包模块覆盖了外部的模块。

    from . import B 
    
    或 
    
    from ..A import B
    # .代表当前模块,..代表上层模块,...代表上上层模块,依次类推。
    

    比如一个 package 下有 a.py 和 b.py 两个文件,在 a.py 里 from . import b 即是相对导入 b.py。

    # a.py
    from . import b
    

    Q: 为什么能在 b.py 中 import a 呢?
    A: 这是因为这两个文件所在的目录不是一个包,那么每一个 python 文件都是一个独立的、可以直接被其他模块导入的模块。就像导入标准库一样,它们不存在相对导入和绝对导入的问题。相对导入与绝对导入仅用于包内部。

    Python2.x 默认为相对路径导入,Python3.x 默认为绝对路径导入。
    绝对导入可以避免导入子包覆盖掉标准库模块(由于名字相同,发生冲突)。
    如果在 Python2.x 中要默认使用绝对导入,可以在文件开头加入如下语句:

    from __future__ import absolute_import 
    # 在 3.0 以前的旧版本中启用相对导入等特性所必须的 future 语句,表示打开了 Python 3.0 的默认绝对搜索路径特性
    

    需要注意的是文件夹被python解释器视作package需要满足两个条件:

    • 1.文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。
    • 2.不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。

    所以,当用.. 或 ../..返回上级去导入的时候,如果到了程序的入口就会报错:ValueError: attempted relative import beyond top-level package
    这是因为第2条的原因,也就是相对导入的时候不能返回到顶层目录去导入,否则会报错。
    所以,用绝对导入的人比较多,相对导入中一个点(同级导入)用的比较多。

  • 相关阅读:
    自我介绍
    软工第一次编程作业
    软件定义网络第一次作业
    软工个人总结
    实验 7: OpenDaylight 实验——Python 中的 REST API 调用
    实验 6:OpenDaylight 实验——OpenDaylight 及 Postman 实现流表下发
    软工结对编程作业
    实验 4 : Open vSwitch 实验——Mininet 中使用 OVS 命令
    软件定义网络第三次作业
    软件定义网络第二次作业
  • 原文地址:https://www.cnblogs.com/schips/p/12148092.html
Copyright © 2011-2022 走看看