深入了解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.py
,b1.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.py
时sys.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.py
时sys.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声明的主要内容,如果未能解决你的问题,请参考以下文章