Python-模块和包
from…import…😀
一. 模块与包的意义
1.1 什么是模块?
在Python中,一个.py文件就称之为一个模块(Module)。
1.2 为什么要使用模块?
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。
1.3 什么是包?
如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录(文件夹)来组织模块的方法,称为包(Package)。
包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含
__init__.py
文件的目录)每一个包目录下面都会有一个
__init__.py
的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。它可以是空文件,也可以有Python代码,因为__init__.py
本身就是一个模块。import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的
__init__.py
,导入包本质就是在导入该文件。文件夹里面还可以包含文件夹(可以有多级目录,组成多级层次的包结构)。但是每一个文件夹下面必须有一个
__init__.py
文件。自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。
举例说明:
有个包按照如下目录存放文件:
mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。现在,**
abc.py
** 模块的名字就变成了mycompany.abc
,类似的,**xyz.py
** 的模块名变成了mycompany.xyz
。
类似的,可以有多级目录,组成多级层次的包结构。比如如下的目录结构:
mycompany
├─ web
│ ├─ __init__.py
│ ├─ utils.py
│ └─ www.py
├─ __init__.py
├─ abc.py
└─ xyz.py
文件
www.py
的模块名就是mycompany.web.www
,两个文件utils.py的模块名分别是mycompany.utils
和mycompany.web.utils
总结
模块是一组Python代码的集合,可以使用其他模块,也可以被其他模块使用。
创建自己的模块时,要注意:
- 模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
- 模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。
二. 使用模块 -- 无包组织
使用模块的几种语句:
- import 语句:
import module1[, module2[,... moduleN]
- from … import 语句:
from modname import name1[, name2[, ... nameN]]
- from … import * 语句:
from modname import *
- __name__属性: 用来分清该模块是调用者还是被其他模块调用。
- dir() 函数: 用来查找模块中定义的名字,返回一个有序字符串列表。
2.1 import 语句
想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:
1 | import module1[, module2[,... moduleN] |
使用 Python 源文件,只需在另一个源文件里执行 import 语句。
一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
调用者引用模块后可以:
模块名.函数名(参数)
来使用。
举例说明:
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。如想要导入模块 support,需要把命令放在脚本的顶端:
1 | support.py 文件代码 |
2.2 from … import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,这种访问函数时可以直接使用函数名而不需要前缀,语法如下:
1 | from modname import name1[, name2[, ... nameN]] |
举例说明:
例如,要导入模块 fibo 的 fib 函数,使用如下语句:
1 | fibo.py |
2.3 from … import * 语句
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
这种方法,可以一次性的把模块中的所有(函数,变量)名称都导入到当前模块的字符表。
这将把所有的名字都导入进来,但是那些由单一下划线(_)开头的名字不在此例。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
1 | from modname import * |
三. 使用模块 -- 有包组织
目录只有包含一个叫做
__init__.py
的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做 string)不小心的影响搜索路径中的有效模块。最简单的情况,放一个空的
__init__.py
就可以了。当然这个文件中也可以包含一些初始化代码或者为(将在后面介绍的)__all__
变量赋值。
1. import 语句:
用户可以每次只导入一个包里面的特定模块,他必须使用全名去访问:
1 | import 包名.子包名.模块名 导入模块 |
2. import …from 语句:
同样会导入子模块,他不需要那些冗长的前缀,只需要模块名.函数名(参数)
即可,推荐使用!
1 | from 包名.子包名 import 模块名 导入模块 |
3. import …from 语句:
还有一种变化就是直接导入一个函数或者变量:
1 | from 包名.子包名.模块名 import 函数名 导入模块 |
4. import …from * 语句:
注意:这种导入方法必须要注意
__init__.py
里面的属性__all__
已经设置好。__all__
是用于控制from…import *
Python 会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。但是很不幸,这个方法在 Windows平台上工作的就不是非常好,因为Windows是一个大小写不区分的系统。
在这类平台上,没有人敢担保一个叫做 ECHO.py 的文件导入为模块 echo 还是 Echo 甚至 ECHO。
1 | from 包名.子包名 import * 导入所有模块 |
具体使用方法请看下面章节四。
总结使用时注意事项:
- 注意当使用
from package import item
这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。 - import语法会首先把item当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,恭喜,一个:exc:ImportError 异常被抛出了。
- 反之,如果使用形如
import item.subitem.subsubitem
这种导入形式,最后一项可以是包或者模块(不可以是类,函数或者变量的名字),除了最后一项,都必须是包。。
四. __init__、__all__、__name__、__author__、__doc__、dir()函数
4.1 __init__、__all__
在使用from 包名.子包名 import \* 语句
时必须修改__init__.py
文件的__all__
列表变量。
- 如果包定义文件
__init__.py
存在一个叫做__all__
的列表变量,那么在使用from package import *
的时候就把这个列表中的所有名字作为包内容导入。- 作为包的作者,可别忘了在更新包之后保证
__all__
也更新了啊。你说我就不这么做,我就不使用导入*
这种用法,好吧,没问题。这里有一个例子- 这表示当你使用
from sound.effects import *
这种用法时,你只会导入如下包里面这三个子模块。即这种语法导入的是__all__
指定的模块。- 在python3中,即使包下没有
__init__.py
文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错- import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的
__init__.py
,导入包本质就是在导入该文件。
上述的例子:
1 | __all__ = ["echo", "surround", "reverse"] |
4.1 __name__、__main__
__name__是一个变量。前后加了爽下划线是因为是因为这是系统定义的名字。普通变量不要使用此方式命名变量。
__name__就是标识模块的名字的一个系统变量。这里分两种情况:
- 假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__,即__name__==__main__。可以执行后面的内容;
- 假如此模块是被import的,其值为被调用模块所属的路径。
下面举一个例子:
1 | test1.py |
4.3 __author__、__doc__
文档注释:任何模块代码的第一个字符串都被视为模块的文档注释;
__doc__
:可以访问一个文件中的第一个单引号(1、2、3对)、双引号(1、2、3对)注释的文档。
__author__
:可以将一个文件的作者名字赋给它。
应用示例如下:
1 | # -*- coding: utf-8 -*- |
4.4 dir()函数
内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回 。
无参数: 只能列举当前模块已经被定义的名字;
有参数: 参数只能是已经引用的模块名字,不能为自身名字,否则会报错。
举例子说明:
1 | test3.py |
五. 非公开函数
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;
之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。
private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:
1 | def _private_1(name): |
我们在模块里公开greeting()函数,而把内部逻辑用private函数隐藏起来了,这样,调用greeting()函数不用关心内部的private函数细节,这也是一种非常有用的代码封装和抽象的方法,即:
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。