一. 模块与包的意义
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代码的集合,可以使用其他模块,也可以被其他模块使用。
创建自己的模块时,要注意:
1. 模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
2. 模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。
二. 使用模块 -- 无包组织
使用模块的几种语句:
1. import 语句:import module1[, module2[,... moduleN]
2. from … import 语句:from modname import name1[, name2[, ... nameN]]
3. from … import * 语句:from modname import *
4. __name__属性: 用来分清该模块是调用者还是被其他模块调用。
5. dir() 函数: 用来查找模块中定义的名字,返回一个有序字符串列表。
2.1 import 语句
想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:import module1[, module2[,... moduleN]
- 使用 Python 源文件,只需在另一个源文件里执行 import 语句。
- 一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
- 调用者引用模块后可以:
模块名.函数名(参数)
来使用。
举例说明:
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。如想要导入模块 support,需要把命令放在脚本的顶端:
support.py 文件代码
def print_func( par ):
print ("Hello : ", par)
return
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
test.py 文件代码
# 导入模块
import support
# 现在可以调用模块里包含的函数了
support.print_func("Runoob")
------------------------------------------------------------------------------------------
运行test.py实例输出结果:
Hello : Runoob
2.2 from … import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,这种访问函数时可以直接使用函数名而不需要前缀,语法如下:from modname import name1[, name2[, ... nameN]]
举例说明:
例如,要导入模块 fibo 的 fib 函数,使用如下语句:
fibo.py
# 斐波那契(fibonacci)数列模块
def fib(n): # 定义到 n 的斐波那契数列
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a+b
print() //输出为None
def fib2(n): # 返回到 n 的斐波那契数列
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
return result
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
test.py
from fibo import fib, fib2
print(fib(500))
print(fib2(500))
运行结果:
1 1 2 3 5 8 13 21 34 55 89 144 233 377
None
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
2.3 from … import * 语句
- 这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
- 这种方法,可以一次性的把模块中的所有(函数,变量)名称都导入到当前模块的字符表。
- 这将把所有的名字都导入进来,但是那些由单一下划线(_)开头的名字不在此例。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
from modname import *
三. 使用模块 -- 有包组织
- 目录只有包含一个叫做
__init__.py
的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做 string)不小心的影响搜索路径中的有效模块。 - 最简单的情况,放一个空的
__init__.py
就可以了。当然这个文件中也可以包含一些初始化代码或者为(将在后面介绍的)__all__
变量赋值。
用户可以每次只导入一个包里面的特定模块,他必须使用全名去访问:
import 包名.子包名.模块名 导入模块
包名.子包名.模块名 .函数名(参数) 使用模块
同样会导入子模块,他不需要那些冗长的前缀,只需要模块名.函数名(参数)
即可,推荐使用!
from 包名.子包名 import 模块名 导入模块
模块名.函数名(参数) 使用模块
还有一种变化就是直接导入一个函数或者变量:
from 包名.子包名.模块名 import 函数名 导入模块
函数名(参数) 使用模块
注意:这种导入方法必须要注意Python 会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。但是很不幸,这个方法在 Windows平台上工作的就不是非常好,因为Windows是一个大小写不区分的系统。 在这类平台上,没有人敢担保一个叫做 ECHO.py 的文件导入为模块 echo 还是 Echo 甚至 ECHO。__init__.py
里面的属性__all__
已经设置好。__all__
是用于控制from…import *
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
,导入包本质就是在导入该文件。
上述的例子:
__all__ = ["echo", "surround", "reverse"]
4.1 __name__、__main__
- __name__是一个变量。前后加了爽下划线是因为是因为这是系统定义的名字。普通变量不要使用此方式命名变量。
__name__就是标识模块的名字的一个系统变量。这里分两种情况:
- 假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是main,即__name__==__main__。可以执行后面的内容;
- 假如此模块是被import的,其值为被调用模块所属的路径。
下面举一个例子:
test1.py
if __name__ == '__main__':
print('程序自身在运行')
else:
print('我来自另一模块')
------------------------------------------------------------------------------------------
test2.py
import test1
------------------------------------------------------------------------------------------
运行test2.py输出结果:
我来自另一模块
运行test1.py输出结果:
程序自身在运行
4.3 __author__、__doc__
文档注释:任何模块代码的第一个字符串都被视为模块的文档注释;__doc__
:可以访问一个文件中的第一个单引号(1、2、3对)、双引号(1、2、3对)注释的文档。
__author__
:可以将一个文件的作者名字赋给它。
应用示例如下:
# -*- coding: utf-8 -*-
' a test module '
'fgbhjknml'
__author__ = 'Directoree'
a = 10
print(a)
print(__doc__)
print(__doc__)
print(__author__)
运行结果:
10
a test module
a test module
Directoree
4.4 dir()函数
内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回 。
无参数: 只能列举当前模块已经被定义的名字;
有参数: 参数只能是已经引用的模块名字,不能为自身名字,否则会报错。
举例子说明:
test3.py
# -*- coding: utf-8 -*-
' a test module '
'fgbhjknml'
__author__ = 'Directoree'
a = 10
print(__doc__)
print(__author__)
print(dir())
运行结果:
a test module
Directoree
['__annotations__', '__author__', '__builtins__', '__cached__', '__doc__',
'__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'bbb']
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
test3.py
# -*- coding: utf-8 -*-
import test3
print(dir(test3))
运行结果:
['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__',
'__name__', '__package__', '__spec__', 'a', 'bbb']
['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__',
'__name__', '__package__', '__spec__', 'a', 'bbb']
五. 非公开函数
类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。
private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。