模块化设计
模块化module程序设计理念
模块和包概念的进化史
量变引起质变 + “物以类聚”
语句多了,将实现同一个功能的语句封装一起,产生了函数
将同一类型对象的数据和行为,也就是变量和函数,放到一起,统一管理和调用,就产生了类和对象
将类似功能的函数和类都放到一起,产生了模块
将类似功能的模块放到一起,产生了包
语句 → 函数 → 类和对象 → 模块 → 包
- Python程序
- 包 文件夹
- 模块,.py
- 语句
- 对象、类
- 语句
- 模块,.py
- 包 文件夹
标准库模块 standard library
标准库模块、用户自定义模块
标准模块提供了操作系统功能、网络通信、文本处理、文件处理、数学运算等基本功能
random、math、time、file文件处理、sys和解释器交互、os和操作系统交互……
第三方模块:科学计算、WEB开发、大数据、人工智能、图形系统等
模块化编程 modular programming
讲一个任务分解成多个模块,美国模块都是一个积木,编译后期反复使用、反复搭建
重要优势:
- 便于分解任务,分成多模块实现团队协同开发、完成大规模程序
- 实现代码复用
- 可维护性强
模块化编程的流程
- 设计API,进行功能描述
- 编码实现API中描述的功能
- 在模块中编写测试代码,并消除全局代码
- 使用私有函数实现,不被外部客户端调用的模块函数
模块的API功能描述要点
API,application programming interface,应用程序编程接口,用于描述模块中提供的函数和类的功能描述和使用方式描述
模块化编程中,首先设计的就是模块的API,即要实现的功能描述,然后开始编码实现API中描述的功能,最后,在其它模块中导入本模块进行调用
可以通过help(模块名)
查看模块的API,一般使用时,先导入模块,然后通过help函数查看
import模块后,按住ctrl键,点击模块名称,也可以查看
还可以在python的api文档中查询,进入python安装目录,docs子目录
示例API设计
# 设计计算薪水模块的API
"""
用于计算公司员工的薪资
"""
company = "北京尚学堂" # 全局变量的定义
def yearSalary(monthSalary):
"""根据传入的月薪的值,计算出年薪:monthsalary*12"""
pass
def daySalary(monthSalary):
"""根据传入的月薪,计算出1天的薪资,一个月按照22.5天算"""
pass
以上模块只有功能描述和规范,需要编码人员按需求完成
.__doc__
获取模块说明
操作:获取Salary模块的说明
import math
import Salary
print(Salary.__doc__)
print(Salary.daySalary.__doc__)
模块的创建和测试代码
每个模块都有一个额名称,通过__name__
可以获取模块名称
正常来说,模块名称就对应源文件的文件名。仅有一个例外,当一个模块被作为程序入口的时候,__name__
的值为__main__
import math
math.__name__ # 输出"math"
根据这个特点,将模块源代码文件中的测试代码进行独立处理
if __name__ == "__main__":
print("当前该模块在进行独立运行,做测试")
模块导入
import语句导入
格式:
import 模块名 # 导入一个模块
import 模块1, 模块2,…… # 导入多个模块
import 模块名 as 模块别名 # 导入模块并使用新名字
import 加载的模块氛围四个通用类别
- 使用Python编写的代码,.py文件
- 已经被编译成共享库或DLL的C或C++扩展
- 抱哈一组模块的包
- 使用C编写并连接到Python解释器的内置模块
一切都是对象,当用import 导入一个模块的时候,Python解释器进行执行,最终会生成一个对象,这个对象就代表了被加载的模块
import math
print(id(math))
print(type(math))
print(math.pi) # 通过math.成员名来访问模块中的成员π
from…import导入
导入模块中的成员
尽量避免使用这个导入方法
from 模块名 import 成员1,成员2...
import语句和from…import语句的区别
import,导入的是模块,类似于导入的是文件
from…import,导入的是一个函数/类,类似于导入的是文件中的内容
模块的加载问题
导入一个模块时,模块中的代码都会被执行,不过再次导入该模块,则不会再次执行
一个模块无论被导入多少次,这个模块在整个解释器进程内,有且仅有一个实例对象,就是id不变
__import__()
动态导入
import本质是调用内置函数__import__()
s = "math"
m = __import__(s)
m.pi
importlib
动态导入
import importlib
a = importlib.import_module("math")
print(a.pi)
除了可以进行动态导入,也可以实现在导入了一个模块后,多次加载该模块,打破import only once的导入机制(即模块在Python中一旦被导入,就会执行加载,但之后无论导入多少次都不会再被重新加载)
我的小结:动态导入好像就是之后可以通过更改导入的模块的名称,来更改导入的模块
包 package
包的概念和结构
类似于文件夹
当一个项目中模块很多的时候,需要在进行组织。
本质上,包就是一个必须有__init__.py
的文件夹,也就是一个文件夹如果有这个文件,就是一个包,否则就是一个文件夹
包下面可以包含“模块module”,也可包含子包 subpackage
注意:每个包里都有__init__.py
文件,子包也是,每一个子包都是
导入包
import a.aa.module_AA导入a包下aa包下的module_AA模块,要用带包的完整模块名调用a.aa.module_AA()
from a.aa import module_AA 导入a包下aa包下的module_AA模块,可以直接用模块名调用module_AA()
from a.aa.module_AA import fun_AA 导入函数,可以直接使用函数名fun_AA()
包中的init文件
每个包里的__init__.py
文件就是一个初始化文件,可以导入必须的其它模块等
当导入这个包的时候,都会自动执行这个初始化文件
尽量保持这个文件的简洁
模糊导入
import *
不建议使用
包内引用
from .. a.aa import *
从父级目录a中的包aa中的__all__
定义的模块
from . import module_B1
从同级目录中导入模块
模块搜索路径
模块搜索路径顺序
导入模块的时候,必定有搜索路径,Python是根据什么规则去找各个模块?
Python解释器会按照以下顺序逐级往下找:
- 内置模块
- 当前目录
- 程序的主目录
- pythonpaht目录(如果已经设置了)
- 标准链接库目录
- 第三方目录库(site-package目录)
- .pth文件的内容(如果有)
- sys.path.append()临时添加的目录,只有这个是临时有效的
sys.path
当任何一个python程序启动的时候,都会将上面这些路径收集,并放入sys.path
属性中(sys模块中的path属性)
import sys
for i in sys.path:
print i
第一次结果:
D:\Documents\pythonProject\mypro_modules\b # 没有环境变量
D:\Documents\pythonProject
D:\Program Files\JetBrains\PyCharm 2022.2.2\plugins\python\helpers\pycharm_display
C:\Users\meeki\AppData\Local\Programs\Python\Python311\python311.zip # 标准库,但现在是在系统安装的,不是虚拟环境 ven才是虚拟环境
C:\Users\meeki\AppData\Local\Programs\Python\Python311\DLLs # 标准库文件
C:\Users\meeki\AppData\Local\Programs\Python\Python311\Lib # 标准库文件
C:\Users\meeki\AppData\Local\Programs\Python\Python311 # 标准库文件
D:\Documents\pythonProject\venv
D:\Documents\pythonProject\venv\Lib\site-packages # 第三方库文件
D:\Program Files\JetBrains\PyCharm 2022.2.2\plugins\python\helpers\pycharm_matplotlib_backend
修改虚拟环境的解释器
好处:脱离安装的Python,内部有一个虚拟环境
修改方式:❓我这里没有虚拟环境可选…
配置windows的环境变量
我的电脑 → 右键 → 属性 → 高级系统设置 → 高级 → 环境变量 → 新建系统变量 → 变量名pythonpath → 变量值d:/,e:/
多个就用逗号隔开
.pth
文件的写法
可以再site-packages目录下添加.pth
#一行一个目录
g:\a
g:\b
g:\c
每行一个目录,并且文件名写成.pth.
才能创建成果
模块发布(这部分照做就行)
开发了模块后,要发布,别人可以用第三方扩展库的方式使用我们的模块
- 本地发布
- 上传PyPI
本地发布
模块的本地发布
- 创建一定结构的文件夹
- 创建名为setup.py文件
- 构建一个发布文件
- 在本地安装该模块
- 进入setup.py所在的文件夹,open with terminal, 输入
python setup.py install
- 安装成功后,在site-packages这个存放第三方模块库的文件夹中会出现,而且可以调用了
- 进入setup.py所在的文件夹,open with terminal, 输入
PyPI官网发布
把模块上传到Python官网上,作为一个真正的第三方库,成为可以给所有人自由使用的公共资源
- 创建账户
- 用户文件
- 上传、远程发布
- 管理你的模块
- 让别人使用
都是死的步骤,照做就可以了
创建账户
进入官网:https://pypi.org
创建账户
创建用户信息文件
方式1:使用命令(linux)
输入并执行后 python setup.py register
,输入用户名和密码
方式2:使用文件(windows、linux)
在用户的家目录建一个名为.pypirc的文件,内容:
[distutils]
index-servers=pypi
[pypi]
repository = https://upload.pypi.org/legacy/
username = 账户名
password = 你自己的密码
linux家目录:~/.pypirc
windows家目录:c:/user/用户名
上传并远程发布
进入setup.py所在目录
右键,open in terminal
键入,python setup.py sdist upload
就可以将模块代码上传并发布了
管理你的模块
登录pypi
导航栏可以看到管理入口
让别人使用你的模块
过一段时间,索引可以搜到
把发布的模块安装在自己的本地:
- Pycharm安装
- Pycharm → file → settings → project interpreter → 加号+ install → PyPI服务器上搜索 → 点击Install Package
- 命令行安装
pip install package-name