大部分程序员写python程序的第一行代码往往是import xxx,当然,有部分程序员会在开头写上解释器的执行路径和代码文件所用的编码类型,如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
这是个好习惯,我个人也是提倡在开头写上这个。
言归正传,开头就写上import xxx 或 from yyy import xxx(后面会说到这两种导入方式的区别),是做什么用的呢?
在Python中,import语句是用来导入其他python文件(这些文件在Python中称为模块module),就可以在代码中使用该模块里定义的变量、常量(其实也是变量)、类或者函数,从而达到减少程序的代码量和提高可维护性的目的。
为了方便讲述,我在本地创建目录文件,用实例来说明import的用法。
本地目录和文件如下:
workplace
|____ t1.py
|____ t2.py
|____ testdir
|____ __init__.py
|____ t3.py
t1.py代码如下:
import t2
t2.sayHello()
t2.py代码如下:
def sayHello():
print('hello,i am t2')
t3.py代码如下:
def sayHello():
print('hello,i am t3')
在命令行中输入python t1.py运行,结果为hello,i am t2,能正常打印结果,说明import xxx导入是没有问题的,这也是第一种导入方式。
现在解释第一种导入方式,这句代码import xxx,xxx其实是模块名module_name。
Python import 导入模块时的搜索路径
在当前目录下搜索该模块
在环境变量PYTHONPATH中指定的路径列表中依次搜索
在 Python 安装路径的 lib 库中搜索
在 Python 程序启动时会自动将 当前目录(完整路径或用一个''表示)、PYTHONPATH 设置的目录、.pth 文件里的目录、标准库目录合并成一个 list ,组成每次 import 时 Python 搜索的目录列表,放到sys.path 中。
那要是想在t1.py中导入t3.py,该如何导入呢?直接import t3吗?很抱歉,解释器会提示ModuleNotFoundError: No module named 't3',这里就要用到第二种导入方式:from testdir import t3。
更改后的t1.py代码如下:
from testdir import t3
t3.sayHello()
命令行中执行,正常显示hello,i am t3。
现在解释第二种导入方式,from package_name import module_name。Python把模块组成的集合称为包(package),其实就是一个目录(文章后面也会详情说明包的含义)。与第一种导入方式类似,Python会在运行文件目录和sys.path这两个地方寻找包,然后导入包中名为module_name的模块。
如果在testdir目录下新建t4.py文件,t4.py的代码如下:
def sayHello():
print('hello,i am t4')
然后t3中导入t4,修改后t3.py的代码如下:
import t4
def sayHello():
t4.sayHello()
print('hello,i am t3')
在命令行中运行t1.py就会报错了,提示ModuleNotFoundError: No module named 't4'。
为什么会报错呢?我们来看一下导入流程:t1使用from testdir import t3导入t3,然后在t3.py中用import t4导入t4。问题就出在这里了,t4.py和t1.py不在同一目录下,是不能直接使用import t4导入t4的。
对于上面的错误,使用python2运行t1.py是不会报错的,因为在python2中,import默认使用的是相对导入,而在python3中,却是使用绝对导入。
import中最关键的部分——相对导入和绝对导入
相对导入与绝对导入,这两个概念是相对于包内模块导入而言的。
所谓的包(package),就是包含多个相关联的模块以及__init__.py文件的目录,__init__.py文件在包导入时会被首先执行,包的作用是便于维护和使用模块,同时能有限的避免命名空间的冲突。
包中的__init__.py 文件通常为空,但可以为它增加其他的功能。在导入一个包时,实际上是导入了它的__init__.py文件。这样就可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入。
__init__.py中还有一个重要的变量all, 它用来将模块全部导入。
from package import module1
from package import module2
__all__ = ["module1", "module2"]
有了包的概念,接下来,我们回到之前的那个import t4导致的问题,在Python3.x 中
import t4 # 是隐式相对引入(就是相对于当前运行文件所在的目录)
from . import t4 # 是显式相对引入
from testdir import t4 # 是绝对引入
官方推荐的第三种,第一种是不推荐的,它只能用于导入 sys.path 中的模块。
根据上面的导入方式,修改后t3.py的代码如下:
from testdir import t4
def sayHello():
t4.sayHello()
print('hello,i am t3')
运行结果:
hello,i am t4
hello,i am t3
最后总结一下,包是归类相关联模块的目录,使你的项目看起来清晰明了,而上面提到的相对导入与绝对导入仅针对于包内模块之间的导入而言,主程序想使用包下面的某些模块或全部模块时,可以使用以下语句来导入:
from package_name import module_name #指定包下面的某一模块
或
from package_name import * #包下面的全部模块