模块
1.模块化(module)程序设计理念
1.1模块和包概念
我们将实现同一个功能的语句封装起来就是“函数”
我们将同一类型对象的“数据行为”,也就是“变量和函数”,放到一起同一管理和调用,就形成了“类和对象”
我们将实现类似功能的函数和类放到一起就是“模块”
我们将实现类似功能的模块放到一起就是“包”
- python程序由模块组成。一个模块对应python源文件,一般后缀名是:.py
- 模块由语句构成。运行python程序时,按照模块中语句的顺序依次执行。
- 语句是python程序的构造单元,用于创建变量、变量赋值、调用函数、控制语句等。
1.2标准库模块(standard library)
与函数类似,模块也分为标准库模块和自定义模块。
python标准库提供了操作系统功能、网络通信、文本处理、文件处理、数学运算等基本的功能。例如:random(随机数)、math(数学运算)、time(时间处理)、file(文件处理)、os(和操作系统交互)、sys(和解释器交互)等、另外python还提供了海量的第三方模块,使用方式和标准库类似。
1.3为什么需要模块化编程
模块对应于python源代码文件(.py文件)。模块中可以定义变量、函数、类、普通语句,这样可以将一个python程序分解成多个模块,便于后期的重复应用。
模块化编程(Modlar Porgrmming)将一个任务分解成多个模块。每个模块就像搭积木一样,便于后期的反复使用、反复搭建。
模块化编程有如下几个重要优化:
- 便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
- 实现代码复用。一个模块实现后,可以反复调用
- 可维护型增强
1.4模块化编程的流程
模块化编程的一般流程:
- 设计API,进行功能描述。
- 编码实现API中描述的功能。
- 在模块中编写测试代码,并消除全局代码。
- 使用私有函数实现不被外部客户端调用的模块函数
1.5模块的API和功能描述要点
API(Application Porgramming Inerface 应用程序编程接口)是用于描述模块中提供的函数和类的功能描述和使用方法描述。
模块化编程中,首先设计的就是模块的API(即要实现的功能描述),然后开始编码实现API中描述的功能,最后,在其他模块中导入本模块进行调用。
可以通过help(模块名)查看模块的API。一般使用时先导入模块,然后通过help函数查看。
"""
说明:
用于计算公司员工的薪资
"""
company = "公司"
def yearSalary(monthSalary):
"""根据传入的月薪值,计算年薪:monthsalary*12"""
pass
def daySalary(monthSalary):
"""根据传入的月薪值,计算出1天的薪资,一个月22天"""
pass
如上模块只有功能描述和规范,需要编码人员按照要求实现代码
1.6模块的创建和测试代码
每个模块都有一个名称,通过特殊变量name可以获取模块的名称,在正常情况下,模块名字对应源文件名,它的name的值为“main”。我们可以根据这个特点,将模块的源代码文件中的测试代码进行独立的处理。
例如:
improt math
math.__name__ #输出‘math’
#coding=utf-8
"""
说明:
本模块用于计算公司员工的薪资
"""
company = "公司"
def yearSalary(monthSalary):
"""根据传入的月薪值,计算年薪:monthsalary*12"""
return monthSalary*12
def daySalary(monthSalary):
"""根据传入的月薪值,计算出1天的薪资,一个月22天"""
return monthSalary//22.5
if __name__=="main": #测试代码
print(yearSalary(3000))
print(daySalary(3000))
1.7模块文档字符串和API设计
我们可以在模块的第一行增加一个文档字符串,用于描述模块的相关功能。然后,通过doc可以获得文档字符串的内容。
import salary
print(salary.__doc__)
print(salary.yearSalar.__doc__)
2.模块的导入
模块化设计的好处之一就是“代码复用性高”。写好的模块可以被反复调用,重复使用。模块的导入就是“在本模块中使用其他模块”
2.1import语句导入
import语句的基本语法格式如下:
import 模块名 #导入一个模块
import 模块1,模块2... #导入多个模块
import 模块名 as 模块别名 #导入模块并使用新名字
import加载的模块分为四个通用类型:
- 使用python编写的代码(.py)
- 已被编译为共享库或DLL的C或者C++扩展
- 包好一组模块的包
- 使用C编写并链接到python解释器的内置模块
我们一般通过import语句实现模块的导入和使用,import本质上使用了内置函数impoort()
>>> import math
>>> id(math)
1311891212784
>>> type(math)
<class 'module'>
>>> import math,turtle
>>> id(math)
1311891212784
>>> import math as m
>>> id(m)
1311891212784
>>> m = math
>>> math.sin(3.14)
0.0015926529164868282
>>>
2.2from…import导入
python中可以使用from…import导入模块中的成员。基本语法格式如下:
from 模块名 import 成员, 成员2, ...
如果希望导入一个模块中的所有成员,则可以采用如下方式:
from 模块名 import *
>>> from math import pi,sin
>>> sin(3.14)
0.0015926529164868282
2.3import语句和from…import语句的区别
import导入的是模块。from…import导入的是模块中的一个函数/一个类
如果进行类比的话,import导入的是“文件”,我们要使用“文件”下的内容,必须前面加“文件名称”,from…import导入的是文件下的“内容”,我们直接使用这些“内容”即可,前面也不需要加“文件名称”了
calculator模块
import测试
form…import测试
2.4import()动态导入
import语句本质上就是调用内置函数import(),我们可以通过它实现动态导入。给import()动态传递不同的参数值,就能导入不同的模块。
>>> s = "math"
>>> m = __import__(s)
>>> print(m.pi)
3.141592653589793
>>> m.sin(3)
0.1411200080598672
注意:
一般不建议我们自行使用import(s)导入,其行为在python2和python3中有差异,会导致意外错误。如果需要动态导入可以使用importlib模块
>>> import importlib
>>> a = importlib.import_module(s)
>>> a.pi
3.141592653589793
2.5模块加载问题
当导入一个模块时,模块中的代码都会被执行,不过,如果再此导入这个模块;则不会再次执行;python这么设计是因为,导入模块更多的时候需要的是定义,模块的变量、函数、对象等。为了优化提高运行效率。
一个模块无论导入多少次,这个模块在这个解释器进程内有且只有一个对象
print("test模块被加载了")
import test #会执行test模块中的语句
import test #不会执行test模块的语句
#######################################
import importlib
import reload(test)#可以重新加载test模块语句
3.包package的使用
3.1包(package)的概念和结构
当一个项目中有很多模块时,需要进行组织。我们将功能类似的模块放到一起,就形成了“包”。本质上,“包”就是一个必须有init.py的文件夹。典型结构如下:
包下面可以包含“模块(module)”,也可以再包含“子包(subpackage)”,就像文件夹下面可以有文件,也可以有子文件夹一样。
3.3导入包操作和本质
导入包的方式如下:
import a.aa.module_AA
在使用时,必须加完整名称来引用。比如:a.aa.module_AA.fun_AA()
from a.aa import module_AA
在使用时,直接可以使用模块名。 比如:module_AA.fun_AA()
from a.aa.module_AA import fun_AA 直接导入函数
在使用时,直接使用函数名。 比如:fun_AA()
注:
- from package import item 这种语法中,item可以是包、模块,也可以函数、类、变量
- import item1.item2 这种语法中,item必须是包或者模块,不能使其他
导入包的本质:
导入包的本质就是“导入了包的init.py”文件。也就是说,“import pcak1”意味着执行了包pack1下面的init.py文件。这样可以在init.py中批量导入我们所需要的模块,而不在需要一个个导入。
init.py的三个核心作用:
- 作为包的标识,不能删除
- 用来实模糊导入
- 导入包实质上是执行init.py文件,可以在init.py文件中做这个包的初始化、以及需要的统一执行代码、已经批量导入。
3.4用*导入包
import * 这样的语句理论上是希望文件系统找出包的所有子模块,然后导入它们。这会花很长时间。python提供了一个明确的包索引。
这个索引是由init.py定义all变量,该变量为列表,在a包中下的init.py中,可定义__all__ = ["module_A","modeule_A2"]
,这意味着from a import *
会从对应的包中导入以上两个子模块。
注:
尽管提供import * 的方法,但仍不建议使用
3.5包内引用
如果是子包内的引用,可以按相对位置引入子模块,以aa包下的module_AA中导入a包下内容为例:
from..import module_A #..表示上级目录 ./表示同级目录
from.import module_A2 #.表示同级目录
3.6sys.path和模块搜索路径
当导入某个模块文件时,python解释器会按照如下路径寻找模块文件(按照顺序不停的继续往下找):
- 内置模块
- 当前目录
- 程序的主目录
- pythonpath目录(如果已经设置了pythonpath环境变量)
- 标准链接库目录
- 第三方库目录(site-package目录)
- .pth文件的内容(如果存在的的话)
- sys.path.append()临时添加的目录
当任何一个python程序启动时,就将上面的这些搜索路径(出内置模块以外的路径)进行收集,放到sys模块的path属性中(sys.path)。
.pth文件的写法
我们可以字site-packages目录下添加.pth文件。并添加内容:
#一行一个目录
g:\a
g:\b
g:\c
注:
- 确保g:\a,g:\b,g:\c对应的目录真是存在。
- 在windows系统中建立.pth文件,由于没有文件名不能直接建立需输入:“.pth.”才能正常建立。
4.模块的发布和安装
4.1模块的本地发布
当我们完成了某个模块的开发后,可以将他对外发布,其它开发者也可以以“第三方扩展库”的方式使用我们的模块。
按照如下步骤:
- 为模块文件创建如下结构的文件夹(一般,文件夹的名字和模块的名字一样):
- 在文件夹中创建一个名为【setup.py】文件,内容如下: ```python from distutils.core import setup
setup( name=’SuperMah’, #对外我们模块的名字 version=’1.1’, #版本号 description=’这是第一个对外发布的模块(测试)’, author=’puke’, #作者 author_email=’123456@email.com’, py_modules=[‘SuperMath.demo1’,’SuperMath.demo2’] #要发布的模块 )
3. 构建一个发布文件,通过终端,cd到模块文件夹c下面,再键入命令:
`python setup.py sdist`
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649986315796-895b4089-4645-43ed-994e-408bf28e0c7e.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=222&id=u73b0d6d5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=597&originWidth=1131&originalType=binary&ratio=1&rotation=0&showTitle=false&size=121725&status=done&style=shadow&taskId=ub51ac0ce-ea68-47b4-b0cf-c926d06bc62&title=&width=421)
执行完成后如下:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649986915260-7e5a0f8f-c8a7-4d7d-8bca-274284c0f7f7.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=297&id=u232f29b9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=636&originWidth=1070&originalType=binary&ratio=1&rotation=0&showTitle=false&size=130020&status=done&style=shadow&taskId=u067a601a-364e-4837-80fa-6088b770230&title=&width=500)
<a name="nxWmB"></a>
###
<a name="Sa0So"></a>
### 4.2本地安装模块
将发布安装到你的本地计算机上。仍在cmd命令模式下操作,进入setup.py所在目录,键入命令:
`python setup.py install`
安装成功后,我们进入python目录/Lib/site-packages目录(第三方模块都安装在这里,python解释器执行时也会搜索这个路径)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649987311698-db7fe9c1-77b9-4a42-98da-2729a586be6b.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=203&id=u74d57eca&margin=%5Bobject%20Object%5D&name=image.png&originHeight=414&originWidth=859&originalType=binary&ratio=1&rotation=0&showTitle=false&size=87218&status=done&style=shadow&taskId=ue2bbcc65-126f-4df3-9d00-ea0a3d81b47&title=&width=421.20001220703125)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649987569979-8bdc8ffe-74a6-44e1-8082-b86f979ae7df.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=163&id=ub6e3f3d9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=432&originWidth=1419&originalType=binary&ratio=1&rotation=0&showTitle=false&size=186234&status=done&style=shadow&taskId=u87cde161-e896-4115-ad8f-ae0964727cd&title=&width=536)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649987751926-249f4061-b534-4663-a674-0f4e7f3b9902.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=213&id=u345d6cdb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=308&originWidth=716&originalType=binary&ratio=1&rotation=0&showTitle=false&size=40340&status=done&style=shadow&taskId=u66804060-11e7-447d-832e-578a07798dd&title=&width=494.79998779296875)<br />可直接引用
<a name="YVTp6"></a>
### 4.3上传模块到PyPI
- 注册PyPI
网站:[https://pypi.org/](https://pypi.org/)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/1315343/1649988053396-f4e15897-1995-450b-bfa5-69d03d017fc4.png#clientId=u19c81f6c-3d37-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=272&id=u2f8b25fd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=803&originWidth=764&originalType=binary&ratio=1&rotation=0&showTitle=false&size=60674&status=done&style=shadow&taskId=u35433ea7-b994-442f-ae7f-0bae48de1e0&title=&width=259.20001220703125)
在c:/user/用户名目录创建文件名为.pypirc内容为:
```python
[distutils]
index-servers=pypi
[pypi]
repository=https://upload.pypi.org/legacy/
username= 账户名
password= 密码