相信使用过Python编写代码的同学,会经常在文件头看到这样的import …,是的,这就是导入模块的语句,而每一个后缀名为.py的文件都是一个模块。
import jieba
import os
逻辑上来说模块是一组功能的组合;实质上一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
import加载的模块分为四个通用类别:
a. 使用python编写的代码(.py文件);
b. 已被编译为共享库或DLL的C或C++扩展;
c. 包好一组模块的包
d. 使用C编写并链接到python解释器的内置模块;
如何使用模块?
想要使用模块,必须先要将模块加载进来,可以通过关键字 import 或 from进行加载;需要注意的是模块和当前文件在不同的命名空间中。
模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句)
1、导入整个模块
比如我们有一个myModule的文件夹,里面有一个first.py文件,文件中的内容如下
a = 1
def myfun(s):
print(s + 1)
在myModule的文件夹下打开终端/cmd,输入python进入命令行交互模式
写完模块导入的语句之后,接着就可以调用该模块下的函数了。调用方式为
>>> import first
>>> a
Traceback (most recent call last):
File "" , line 1, in <module>
NameError: name 'a' is not defined
>>> first.a
1
>>> first.myfun(2)
3
所以说first.py文件就是一个模块,可以用import导入,里面变量和方法都要用first.前缀来引用,如果想不使用这个前缀或是我们只是想要使用模块中的某个函数,就可以只导入该变量或函数。导入方式为:from module_name import function_name。
如果导入的是变量,就可以直接输入变量名来获得变量的值;如果直接导入的是函数,可以直接使用function_name() 的方式调用函数,无需在函数名前面加上模块名。
# 导入变量
>>> from first import a
>>> a
1
# 导入函数
>>> from first import myfun
>>> myfun(3)
4
# 一次导入多个变量
>>> from first import a,myfun
>>> a
1
>>> myfun(5)
6
# 导入模块中全部变量
>>> from first import *
>>> a
1
>>> myfun(5)
6
>>>
3、使用as给模块指定别名
可以在后面使用as给函数指定别名。句式如:import module_name as new_name,
>>> import first as f
>>> f.a
1
>>> f.myfun(6)
7
在上述导入函数的基础上,可以在后面用as语句给导入的函数指定别名。句式如:from module_name import function_name as new_function。
>>> from first import myfun as add
>>> add(8)
9
模块(module) 其实就是py文件,里面定义了一些函数、类、变量等。
包(package) 是多个模块的聚合体形成的文件夹,里面可以是多个py文件,也可以嵌套文件夹。
库是参考其他编程语言的说法,是指完成一定功能的代码集合,在python中的形式就是模块和包。
导入包的本质:导入一个包就是执行包下的__init__.py文件
只要一个文件夹下面有个 init.py 文件,那么这个文件夹就可以看做是一个包。
包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的 init.py 而不是模块里面的语句了。另外,如果只是单纯的导入包,而包的 init.py 中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的。
下面我们来实操进行说明
在myModule文件夹中新建folder文件夹,先cd进入myModule文件夹,在mkdir folder新建folder文件夹
xws@MHQ0063 myModule % mkdir folder
我们想让folder文件夹成为一个包。文件夹里新建abcd.py文件,输入vi abcd.py,文件中内容如下
b = 2
class Myclass:
def __init__(self, name, age):
self.name = name
self.age = age
def get_info(self):
print('my name is {name} and age is {age}'.format(name = self.name, age = self.age))
esc–>:wq退出保存
此时在folder文件夹中新建一个__init__.py文件,否则程序会将这个文件夹当成普通文件夹来处理而不是一个包。这个__init__.py文件中可以什么都不填。
上面步骤操作下来,文件结构如下
我们还是在myModule文件夹下打开命令行,进入python交互模式
>>> import folder
>>> folder.abcd.b
Traceback (most recent call last):
File "" , line 1, in <module>
AttributeError: 'module' object has no attribute 'abcd'
# 只是导入包不能随便使用其中的模块,要导入到具体模块或者变量的层次
>>> from folder import abcd
>>> bob = abcd.Myclass(name = 'Bob', age = 20)
>>> bob.name
'Bob'
>>> bob.get_info()
my name is Bob and age is 20
>>> from folder.abcd import b
>>> b
2
>>> import folder.abcd
>>> abcd.b
2
>>> import folder.abcd as a
>>> a.b
2
注意:
特殊的__init__.py文件
init.py文件其实是一个特殊的文件,它相当于名为folder模块,即如果使用import folder则可以调用在__init__.py文件文件中定义的变量。
将__init__.py文件编写如下
from folder.abcd import b
c = 3
在myModule文件夹下打开命令行,进入python交互模式
>>> import folder
>>> folder.c
3
>>> folder.b
2
>>> from folder import b
>>> b
2
对比之前的from folder.abcd import b,使用__init__.py文件可以将常用的一些变量导入以方便调用。
另外需要注意两点
用import hello时,python会搜寻hello.py文件,搜索顺序如下
先搜寻内置模块是否有hello(因此我们定义的模块名不能内置模块相同)
若内置模块没有,则看以下这些目录里有没有
>>> import sys
>>> sys.path
['', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload', '/Users/xws/Library/Python/2.7/lib/python/site-packages']
其中第一个’‘表示当前的工作路径,我们可以看出安装的第三方包所在路径(‘/Users/xws/Library/Python/2.7/lib/python/site-packages’)也在这个列表之中,所以无论工作路径在哪里,都能搜寻到这些包。建议把模块放在该文件夹下。
__ all __
import *的方式无法导入以下划线开头的变量名_e = 4
__ init__.py文件内容更改如下
from folder.abcd import b
c = 3
_e = 4
python模式下,以下导入方式,在查找变量_e是会报name ‘_e’ is not defined
>>> from folder import *
>>> c
3
>>> _e
Traceback (most recent call last):
File "" , line 1, in <module>
NameError: name '_e' is not defined
但如果指定导入_e便可以
>>> from folder import c
>>> c
3
>>> from folder import _e
>>> _e
4
如果定义了__all__,则import *就可以导入下划线开头的变量
__ init__.py文件内容更改如下
from folder.abcd import b
__all__ = ['c', '_e']
c = b + 1
_e = 4
>>> from folder import *
>>> b
Traceback (most recent call last):
File "" , line 1, in <module>
NameError: name 'b' is not defined
>>> c
3
>>> _e
4
由上面的输出结果,我们可以知道import *只会导入__all__中指定的变量,无论是否以下划线开头。这样限制可以防止import *命令导入太多变量污染命名空间,过滤掉一些中间变量如b
python中的import分为绝对引用和相对引用两种。它们之间的差异在于,引用模块时,定位被引用模块位置 的方式不同。
绝对引用是通过.的连接,指定出最高级文件(夹),到目标文件的绝对路径。我们上面的所有用法都属于绝对引用。
而相对引用是指定待引用模块与当前文件的相对位置,.表示上一级文件
在实际使用中,无论是绝对导入还是相对导入都要注意,如何导入与被调用位置有关。
以下面的文件结构为例
folder1
│ first1.py
│ first2.py
│ init.py
│
└─folder2
second1.py
second2.py
init.py
下面分为两种情况
folder1是一个项目。运行这个项目需要在folder文件夹中打开cmd,运行python first1.py
此时first1.py文件中引用first2.py中变量只需from first2 import sth
不可以from folder1.first2 import sth,也不可以 from .first2 import sth
(即使folder1中有定义_init_.py,在文件夹内部打开cmd仍无法搜索到folder1的名称)
first1.py文件中引用second1.py中变量需要from folder2.second1 import sth
second1.py文件中引用second2.py中变量需要from folder2.second2 import sth
或者使用相对引用方法:from .second2 import sth
(注意first1引用first2 与 second1引用second2 的区别)
folder1是一个包。一般使用时,是在外面的文件夹中import这个包
此时first1.py文件中引用first2.py中变量需要from folder1.first2 import sth
或者from .first2 import sth
不可以 from first2 import sth,即使两个first文件在同一个文件夹内
从上面两个例子的对比中我们可以看出,一个项目内的文件之间,相互引用变量时,如何import是要看这个项目是在什么文件中调用的,也可以说要看这些文件和调用处之间的相对位置。
import运行本质
使用import语句,要明确两件事
(1)执行导入模块命令时,会首先检查待导入的模块是否在当前已有模块之中,如果有则跳过import。因此模块之间相互引用不会导致无限循环。
查看当前已导入模块使用下面方法
import sys
sys.modules
得到结果是一个字典,键是模块名,值是文件所在路径
(2)import语句与文件执行
在这样的文件结构下
myModule
| first.py
|───folder
| | abcd.py
| | __ init __.py
folder是一个package,abcd是一个module
import folder只是导入package,相当于执行__ init__ .py文件
from folder import abcd则执行了__ init __ .py文件文件与abcd.py文件
from folder.abcd import b其实也执行了 __ init __ . py 文件文件与abcd.py文件
(要知道执行了什么,可以在这些文件之中添加print语句,看是否打印出结果)
知道这个执行原理,可以更好理解前面得到的一些结论
首先是在__init__.py文件中什么都没有的情况下,import folder无法调用abcd模块中的变量,是因为相当与运行了一个空文件,没有将整个包导入工作空间
abcd模块中定义了print语句后,import两次,只有第一次会print出值,说明第二次检查出模块已在导入之列,忽略了这条import命令
我们经常会在代码中看到这一句 if __ name__ == ‘__ main__’ ,为了理解它的作用,我们来看下面的例子
在folder文件夹下新建new.py文件,里面内容为
print(__name__)
在folder文件夹下打开命令行,输入
python new.py
返回结果
xws@MHQ0063 folder % python new.py
__main__
在myModule文件夹下打开命令行,进入python交互模式
>>> from folder import new
folder.new
>>> print(__name__)
__main__
>>> print(new.__name__)
folder.new
从测试结果可以发现直接运行文件和import文件是有差异的,差异在于二者的__ name__ 变量不同。__ name__ 变量是一个特殊的变量,每个py文件运行时都会对应一个 __ name__变量,即使在交互模式下也可以查看这个变量值。
所以 if __ name__ == '__ main__'的作用就很好理解了,即import时不执行下面的代码,只有在直接执行这个文件时才运行之后的代码。这算是一种约定俗成的写法,如果不怕文件被import,可以不用这个。
import os 是导入标准库os
os(operation system)import os
os(Operation System)操作系统
有了OS模块,我们不需要关心什么操作系统下使用什么模块,OS模块会帮你选择正确的模块并调用
参考python模块详解