深入了解import声明

Posted johnjim

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入了解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 sa1 from 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声明的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段8——声明函数

白话设计——深入了解LOD

深入了解http协议

如何使用sublime代码片段快速输入PHP头部版本声明

深入了解 Go 语言的方法

深入了解MyBatis二级缓存