zoukankan      html  css  js  c++  java
  • Python:相对导入与绝对导入(import)、os.path、__file__

    Python在导入import包的时候,有绝对导入和相对导入方式。

    • 绝对导入:import p1.m1 或者 from p1 import m1 等。
    • 相对导入:from . import m1 或者 from .. import m1 或者 from ..p1 import m1 或者 from .m1 import f1等。 

    比较而言,绝对导入更为简便清晰,相对导入则可维护性强,但是容易出错。

    首先,有文件结构如下:

    1. 绝对导入:推荐使用 —— 加入了绝对路径,就可以直接import该路径下的模块或者包中的模块

    # test_绝对导入和相对导入.py
    
    import sys, os
    
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))    #先加入绝对路径,否则会报错,注意__file__表示的是当前执行文件的路径
    from package_test import sub_test  #绝对导入,包中模块
    sub_test.sub_packege_test()
    
    # 此时也可使用 import_test模块,因为上面的路径
    import import_test as it   #模块
    it.ss_B()
    
    # 同时,也可以直接指定某个目录,加入搜索路径,然后导入该目录下的模块,例如:
    sys.path.append(os.path.abspath(r'D:Python_workspacespyder_spacemy_init'))

    2. 相对路径稍微复杂 —— 相对导入,则该模块必须有包结构且只能导入它的顶层模块内部的模块(也不能导入和顶层模块同目录的模块)。

    相对导入很重要的一点:相对路径是不是一直在python的package中,如果不在会报错。

    而被python解释为package,需要满足:

    (1)不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口,也就是不能直接执行该文件夹中的文件)。

    (2)文件夹中必须有__init__.py文件。

    其中第(1)点是因为:如果一个模块被直接运行,则此时它自己就是顶层模块,不存在层次结构,所以找不到其他的相对路径;同时此时该文件所在的目录也不能视为package了(虽然该目录下有__init__.py文件)。

    例如,对于上面的文件结构,如果我们执行 test_绝对导入和相对导入.py 模块文件,则该文件此时属于顶层模块,不能通过相对导入(例如 from . import sub_test)来导入该文件的上层目录中的模块或同目录的模块,但是此时可以使用绝对导入

    示例,三种错误:

    # test_绝对导入和相对导入.py
    
    # 错误一
    from .. import import_test
    import_test.ss_B()      # ValueError: attempted relative import beyond top-level package
    
    
    # 错误二
    from . import sub_test   #
    sub_test.sub_packege_test()   # ImportError: cannot import name 'sub_test' from '__main__'
    
    
    # 错误三
    from .sub_test import sub_packege_test
    sub_packege_test()  # ModuleNotFoundError: No module named '__main__.sub_test'; '__main__' is not a package
    • 注意:Python 是根据 __name__ 来决定一个模块在包中的结构的,如果是 __main__ 则它本身是顶层模块,没有包结构

    如果要使用相对导入,怎么办? —— 就要使得所导入的模块在所执行的模块(顶层模块)内部<内层目录>。

    test_绝对导入和相对导入.py移到外层my_init目录下,再执行,则可以成功:

    # sub_test.py
    from . import sub_test_2  #相对导入,此时该目录是package,因为此时不是顶层模块了,也不是和顶层模块同目录或者超出顶层模块,它在顶层模块的内层
    # from .. import import_test  #报错,此时 test_绝对导入和相对导入.py 作为顶层模块,则它所在的目录此时也不算是package了,所以不能用相对导入来导入该目录下的模块
    sub_test_2.sub_packege_test_2()
    
    def sub_packege_test():
        '''testing on the sub_packege_test doc ---'''
        print('it is a sub-package!')
    
    # sub_test_2.py
    def sub_packege_test_2():
        '''testing on the sub_packege_test_2 doc ---'''
        print('it is a sub-package-2!')
    
    
    # 执行文件 test_绝对导入和相对导入.py,作为顶层模块,则它所在的目录此时也不算是package了,所以不能用相对导入来导入该目录下的模块
    from package_test import sub_test
    sub_test.sub_packege_test()

    3. os.path.abspath、os.path.dirname、os.path.realpath

    import sys, os
    
    print(__file__)    #当前.py文件的位置
    print(os.path.abspath(__file__))  #返回当前.py文件的绝对路径
    print(os.path.dirname(os.path.abspath(__file__)))   #当前文件的绝对路径目录,不包括当前 *.py 部分,即只到该文件目录
    print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #返回文件本身目录的上层目录    
    print(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))  #每多一层,即再上一层目录
    
    print(os.path.realpath(__file__))   #当前文件的真实地址
    print(os.path.dirname(os.path.realpath(__file__))) # 当前文件夹的路径
    
    path = os.path.dirname(os.path.abspath(__file__))
    sys.path.append(path)   #将目录或路径加入搜索路径
    
    print(__name__)

    注:

    1. from package_A import module_B/package_B中,先执行的是package_A中的__init__.py文件,再执行后面的module_B文件或者package_B中的__init__.py文件。

    2. 在顶层模块内部的各模块,可以相对导入;这些模块对于顶层模块同目录或者更上层目录则不能相对导入。

    3. 相对导入格式中:每多一个点,表示更上一层目录

    #

    参考:

    https://www.cnblogs.com/lshedward/p/9995704.html

    https://blog.csdn.net/sad_sugar/article/details/78634679

    https://www.cnblogs.com/ArsenalfanInECNU/p/5346751.html

    https://www.jb51.net/article/102252.htm

    https://www.runoob.com/python/python-os-path.html

    https://blog.csdn.net/rainshine1190/article/details/85165059

    https://blog.csdn.net/u011760056/article/details/46969883

  • 相关阅读:
    Media change : please insert the disk labeled
    ubuntu 关闭和开启防火墙
    CentOS6.3上部署Ceph
    Keepalived_vrrp: ip address associated with VRID not present in received packet
    Python 错误和异常小结
    nova network-vif-plugged 事件分析1
    ansible 之条件语句 when
    ansible 判断和循环
    openvswitch dpdk
    ES6之Promise
  • 原文地址:https://www.cnblogs.com/qi-yuan-008/p/12833189.html
Copyright © 2011-2022 走看看