zoukankan      html  css  js  c++  java
  • 深入了解import声明

    import声明即用于导入模块,比如import numpy as np,但是涉及复杂工程目录时容易搞得稀里糊涂,于是我专门使用了python3.7来测试并解决import相关问题。

    基本定义

    • module:即模块,也就是中各种.py文件,模块名就是文件名

    • built-in-module:即内置模块,就是在安装python的时候系统编译在python解释器中的,比如numpy

    • package:任何包含__init__.py文件的文件夹就是一个package。注意根据python document,在python3.3以上中,即使没有__init__.py,文件夹也被自动视作一个package

    • object:即对象,在python中,对象可以是函数,类以及变量等。

    import与sys.path

    如果import导入了一个module,就能运行该module中的所有代码。导入package时,会运行package目录下的__init__.py,然后通过__init__.py运行package目录下的所有module,__init__.py可以是空的,前面讲到在python3.3以上,__init__.py可以没有。

    import会自动在sys.path包含的目录中寻找相应的模块或者包,在一个.py脚本被运行时,sys.path会初始化包含以下目录:

    • PYTHONPATH,即常说的系统环境变量PATH
    • 默认安装的模块目录,比如numpy就在此目录中
    • .py脚本所在的目录,这一点根据脚本所在的目录不同是可以变化的。

    常用的import方式

    常用的import方式有四种:

    import <package>
    
    import <module>
    
    from <package> import <module or subpackage or object>
    
    from <module> import <object>
    

    当然还有

    import <module> as   # 比如 import numpy as np
    import <object> as
    

    场景1:导入系统以及同级目录下的模块

    对于以下的工程目录:

    test/                      # 跟目录
        packA/                 # package packA
            subA/              # subpackage subA
                __init__.py
                sa1.py
                sa2.py
            __init__.py
            a1.py
            a2.py
        packB/                 # package packB (implicit namespace package)
            b1.py
            b2.py
        other.py
        start.py
    

    要在start.py中导入系统numpy模块,以及同级目录下的other模块,只需要:

    import numpy
    import numpy as np # 通常将numpy重命名为np
    import other
    

    然后运行start.py脚本

    场景2:导入子目录下的模块

    如果需要在start.py中导入a1.pyb1.py以及sa1.py模块,只需要在start.py中:

    import packA.a1
    import packB.b1
    import packA.subA.sa1
    

    如果只需要导入比如a1.py某个函数a1_func(),只需要:

    from packA.a1 import a1_func()
    from packA.subA.sa1 import sa1_func() # 跟上面同理
    

    注意在start.py和在a1.py导入sa1.py是不同的,在a1.py需要:

    import subA.sa1
    from subA.sa1 import sa1_func()
    from subA import sa2
    

    因为运行a1.pysys.path的相应目录已经改变,只包含a1.py脚本所在的目录。而对于python3,在start.py是不能跨越子目录直接导入sa1.py的,比如from subA import sa1,但是在python2中可以,下面做个简单的总结:

    运行from packA.subA import sa1from subA import sa1
    start.py OK Py2 OK, Py3 fail (subA not in test/)
    a1.py fail (packA not in test/packA/) OK

    场景3:导入父目录下的模块

    如果需要在a1.py中导入父目录下other.py或者是packB目录下的b1.py,此时就需要对sys.path作出修改了,因为运行a1.pysys.path包含a1.py所在的目录packA,并不包含目录packB以及父目录test
    修改sys.path需要用到sys以及os模块,首先需要知道怎么获取当前目录以及父目录,在a1.py中如下:

    current_path=os.path.dirname(__file__) #当前a1.py所在的目录packA 
    parent_path=os.path.dirname(os.path.dirname(__file__)) #当前a1.py所在的父目录或者说上级目录test
    p_parent_path=os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ##获取上上级目录
    

    下面修改sys.path,对于在a1.py中导入父目录下other.py或者是packB目录下的b1.py,只需要将parent_path加入到```sys.path``即可,

    sys.path.append(parent_path)
    

    然后就可以导入other.py以及b1.py了,完整代码如下:

    import sys
    import os
    # print(os.getcwd())
    # sys.path.append(os.getcwd())
    parent_path=os.path.dirname(os.path.dirname(__file__)) # 获取上级目录
    p_parent_path=os.path.dirname(os.path.dirname(os.path.dirname(__file__))) # 获取上上级目录
    sys.path.append(parent_path) # 修改sys.path
    import other # 导入test下的other
    import packB.b1 # 导入b1
    import packA.a2 #导入a2
    import a2 # 此时sys.path既包含上级目录test也包含当前目录packA,所以跟上面一样
    

    此外顺便提到os.getcwd(),注意该函数是获取当前终端的路径而不是脚本的路径,所以为了避免混淆,建议采用os.path.dirname(__file__)这样的形式。

    要点提炼

    • import最重要的是看sys.path所包含的目录,当我们运行脚本时sys.path会自动包含运行脚本所在的目录
    • python3中不能越级导入,如果sys.path只包含test所在目录,导入sa1.py时,只能import packA.subA.sa1,而不能import subA.sa1,也不能import sa1
    • 接第二点,如果sys.path经过修改后,既包含test所在目录,也包含packA所在目录,那么import packA.subA.sa1import subA.sa1都可以,如果再包含sa1所在目录,那么import sa1也可以
    • 第三点可能会造成困惑,一种建议的习惯就是在每个运行的脚本中加入工程的根目录即test所在目录到sys.path中,然后所有导入按照import packA.subA.sa1的形式从第一级目录追溯到要导入的模块即可,而不是一会import packA.subA.sa1,一会import subA.sa1陷入混淆,只导入当前目录所在的模块依然可以import sa1的形式。
  • 相关阅读:
    增量更新代码步骤记录
    软件缺陷管理基本流程
    数据库语言(三):MySQL、PostgreSQL、JDBC
    eclipse的使用
    数据库语言(二):SQL语法实例整理
    windows下MySql没有setup.exe时的安装方法
    数学:完全独立于实际场景的情况下定义的概念,可以正确的描述世界
    数学语言和程序语言的对比:面向过程与面向集合&命题
    iOS开发之IMP和SEL(方法和类的反射)
    iOS之UIButton的normal和selected状态切换
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13281648.html
Copyright © 2011-2022 走看看