模块

1.模块化(module)程序设计理念

1.1模块和包概念

我们将实现同一个功能的语句封装起来就是“函数”

我们将同一类型对象的“数据行为”,也就是“变量和函数”,放到一起同一管理和调用,就形成了“类和对象”

我们将实现类似功能的函数和类放到一起就是“模块”

我们将实现类似功能的模块放到一起就是“包”

python[进阶三] - 图1

  1. python程序由模块组成。一个模块对应python源文件,一般后缀名是:.py
  2. 模块由语句构成。运行python程序时,按照模块中语句的顺序依次执行。
  3. 语句是python程序的构造单元,用于创建变量、变量赋值、调用函数、控制语句等。

1.2标准库模块(standard library)

与函数类似,模块也分为标准库模块和自定义模块。

python标准库提供了操作系统功能、网络通信、文本处理、文件处理、数学运算等基本的功能。例如:random(随机数)、math(数学运算)、time(时间处理)、file(文件处理)、os(和操作系统交互)、sys(和解释器交互)等、另外python还提供了海量的第三方模块,使用方式和标准库类似。

1.3为什么需要模块化编程

模块对应于python源代码文件(.py文件)。模块中可以定义变量、函数、类、普通语句,这样可以将一个python程序分解成多个模块,便于后期的重复应用。

模块化编程(Modlar Porgrmming)将一个任务分解成多个模块。每个模块就像搭积木一样,便于后期的反复使用、反复搭建。

模块化编程有如下几个重要优化:

  1. 便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
  2. 实现代码复用。一个模块实现后,可以反复调用
  3. 可维护型增强

1.4模块化编程的流程

模块化编程的一般流程:

  1. 设计API,进行功能描述。
  2. 编码实现API中描述的功能。
  3. 在模块中编写测试代码,并消除全局代码。
  4. 使用私有函数实现不被外部客户端调用的模块函数

1.5模块的API和功能描述要点

API(Application Porgramming Inerface 应用程序编程接口)是用于描述模块中提供的函数和类的功能描述和使用方法描述。

模块化编程中,首先设计的就是模块的API(即要实现的功能描述),然后开始编码实现API中描述的功能,最后,在其他模块中导入本模块进行调用。

可以通过help(模块名)查看模块的API。一般使用时先导入模块,然后通过help函数查看。

  1. """
  2. 说明:
  3. 用于计算公司员工的薪资
  4. """
  5. company = "公司"
  6. def yearSalary(monthSalary):
  7. """根据传入的月薪值,计算年薪:monthsalary*12"""
  8. pass
  9. def daySalary(monthSalary):
  10. """根据传入的月薪值,计算出1天的薪资,一个月22天"""
  11. pass

如上模块只有功能描述和规范,需要编码人员按照要求实现代码

1.6模块的创建和测试代码

每个模块都有一个名称,通过特殊变量name可以获取模块的名称,在正常情况下,模块名字对应源文件名,它的name的值为“main”。我们可以根据这个特点,将模块的源代码文件中的测试代码进行独立的处理。
例如:

improt math
math.__name__ #输出‘math’

  1. #coding=utf-8
  2. """
  3. 说明:
  4. 本模块用于计算公司员工的薪资
  5. """
  6. company = "公司"
  7. def yearSalary(monthSalary):
  8. """根据传入的月薪值,计算年薪:monthsalary*12"""
  9. return monthSalary*12
  10. def daySalary(monthSalary):
  11. """根据传入的月薪值,计算出1天的薪资,一个月22天"""
  12. return monthSalary//22.5
  13. if __name__=="main": #测试代码
  14. print(yearSalary(3000))
  15. print(daySalary(3000))

1.7模块文档字符串和API设计

我们可以在模块的第一行增加一个文档字符串,用于描述模块的相关功能。然后,通过doc可以获得文档字符串的内容。

  1. import salary
  2. print(salary.__doc__)
  3. print(salary.yearSalar.__doc__)

image.png

2.模块的导入

模块化设计的好处之一就是“代码复用性高”。写好的模块可以被反复调用,重复使用。模块的导入就是“在本模块中使用其他模块”

2.1import语句导入

import语句的基本语法格式如下:

import 模块名 #导入一个模块
import 模块1,模块2... #导入多个模块
import 模块名 as 模块别名 #导入模块并使用新名字

image.png

import加载的模块分为四个通用类型:

  1. 使用python编写的代码(.py)
  2. 已被编译为共享库或DLL的C或者C++扩展
  3. 包好一组模块的包
  4. 使用C编写并链接到python解释器的内置模块

我们一般通过import语句实现模块的导入和使用,import本质上使用了内置函数impoort()

  1. >>> import math
  2. >>> id(math)
  3. 1311891212784
  4. >>> type(math)
  5. <class 'module'>
  6. >>> import math,turtle
  7. >>> id(math)
  8. 1311891212784
  9. >>> import math as m
  10. >>> id(m)
  11. 1311891212784
  12. >>> m = math
  13. >>> math.sin(3.14)
  14. 0.0015926529164868282
  15. >>>

2.2from…import导入

python中可以使用from…import导入模块中的成员。基本语法格式如下:

from 模块名 import 成员, 成员2, ...

如果希望导入一个模块中的所有成员,则可以采用如下方式:

from 模块名 import *

  1. >>> from math import pi,sin
  2. >>> sin(3.14)
  3. 0.0015926529164868282

2.3import语句和from…import语句的区别

import导入的是模块。from…import导入的是模块中的一个函数/一个类

如果进行类比的话,import导入的是“文件”,我们要使用“文件”下的内容,必须前面加“文件名称”,from…import导入的是文件下的“内容”,我们直接使用这些“内容”即可,前面也不需要加“文件名称”了

calculator模块
image.png

import测试
image.png

form…import测试

image.png

2.4import()动态导入

import语句本质上就是调用内置函数import(),我们可以通过它实现动态导入。给import()动态传递不同的参数值,就能导入不同的模块。

  1. >>> s = "math"
  2. >>> m = __import__(s)
  3. >>> print(m.pi)
  4. 3.141592653589793
  5. >>> m.sin(3)
  6. 0.1411200080598672

注意:
一般不建议我们自行使用import(s)导入,其行为在python2和python3中有差异,会导致意外错误。如果需要动态导入可以使用importlib模块

  1. >>> import importlib
  2. >>> a = importlib.import_module(s)
  3. >>> a.pi
  4. 3.141592653589793

2.5模块加载问题

当导入一个模块时,模块中的代码都会被执行,不过,如果再此导入这个模块;则不会再次执行;python这么设计是因为,导入模块更多的时候需要的是定义,模块的变量、函数、对象等。为了优化提高运行效率。

一个模块无论导入多少次,这个模块在这个解释器进程内有且只有一个对象

  1. print("test模块被加载了")
  1. import test #会执行test模块中的语句
  2. import test #不会执行test模块的语句
  3. #######################################
  4. import importlib
  5. import reload(test)#可以重新加载test模块语句

3.包package的使用

3.1包(package)的概念和结构

当一个项目中有很多模块时,需要进行组织。我们将功能类似的模块放到一起,就形成了“包”。本质上,“包”就是一个必须有init.py的文件夹。典型结构如下:

image.png

包下面可以包含“模块(module)”,也可以再包含“子包(subpackage)”,就像文件夹下面可以有文件,也可以有子文件夹一样。
image.png

3.3导入包操作和本质

导入包的方式如下:

  1. import a.aa.module_AA

在使用时,必须加完整名称来引用。比如:a.aa.module_AA.fun_AA()

  1. from a.aa import module_AA

在使用时,直接可以使用模块名。 比如:module_AA.fun_AA()

  1. from a.aa.module_AA import fun_AA 直接导入函数

在使用时,直接使用函数名。 比如:fun_AA()

注:

  1. from package import item 这种语法中,item可以是包、模块,也可以函数、类、变量
  2. import item1.item2 这种语法中,item必须是包或者模块,不能使其他

导入包的本质:
导入包的本质就是“导入了包的init.py”文件。也就是说,“import pcak1”意味着执行了包pack1下面的init.py文件。这样可以在init.py中批量导入我们所需要的模块,而不在需要一个个导入。

image.png

init.py的三个核心作用:

  1. 作为包的标识,不能删除
  2. 用来实模糊导入
  3. 导入包实质上是执行init.py文件,可以在init.py文件中做这个包的初始化、以及需要的统一执行代码、已经批量导入。

3.4用*导入包

import * 这样的语句理论上是希望文件系统找出包的所有子模块,然后导入它们。这会花很长时间。python提供了一个明确的包索引。

这个索引是由init.py定义all变量,该变量为列表,在a包中下的init.py中,可定义__all__ = ["module_A","modeule_A2"],这意味着from a import * 会从对应的包中导入以上两个子模块。

image.png

注:
尽管提供import * 的方法,但仍不建议使用

3.5包内引用

如果是子包内的引用,可以按相对位置引入子模块,以aa包下的module_AA中导入a包下内容为例:

from..import module_A #..表示上级目录 ./表示同级目录
from.import module_A2 #.表示同级目录

image.png

3.6sys.path和模块搜索路径

当导入某个模块文件时,python解释器会按照如下路径寻找模块文件(按照顺序不停的继续往下找):

  1. 内置模块
  2. 当前目录
  3. 程序的主目录
  4. pythonpath目录(如果已经设置了pythonpath环境变量)
  5. 标准链接库目录
  6. 第三方库目录(site-package目录)
  7. .pth文件的内容(如果存在的的话)
  8. sys.path.append()临时添加的目录

当任何一个python程序启动时,就将上面的这些搜索路径(出内置模块以外的路径)进行收集,放到sys模块的path属性中(sys.path)。
image.png

Snipaste_2022-04-14_17-30-55.png
.pth文件的写法
我们可以字site-packages目录下添加.pth文件。并添加内容:

  1. #一行一个目录
  2. g:\a
  3. g:\b
  4. g:\c

注:

  1. 确保g:\a,g:\b,g:\c对应的目录真是存在。
  2. 在windows系统中建立.pth文件,由于没有文件名不能直接建立需输入:“.pth.”才能正常建立。

4.模块的发布和安装

4.1模块的本地发布

当我们完成了某个模块的开发后,可以将他对外发布,其它开发者也可以以“第三方扩展库”的方式使用我们的模块。
按照如下步骤:

  1. 为模块文件创建如下结构的文件夹(一般,文件夹的名字和模块的名字一样):

image.png

  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’] #要发布的模块 )

  1. 3. 构建一个发布文件,通过终端,cd到模块文件夹c下面,再键入命令:
  2. `python setup.py sdist`
  3. ![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)
  4. 执行完成后如下:
  5. ![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)
  6. <a name="nxWmB"></a>
  7. ###
  8. <a name="Sa0So"></a>
  9. ### 4.2本地安装模块
  10. 将发布安装到你的本地计算机上。仍在cmd命令模式下操作,进入setup.py所在目录,键入命令:
  11. `python setup.py install`
  12. 安装成功后,我们进入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)
  13. ![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)
  14. ![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 />可直接引用
  15. <a name="YVTp6"></a>
  16. ### 4.3上传模块到PyPI
  17. - 注册PyPI
  18. 网站:[https://pypi.org/](https://pypi.org/)
  19. ![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)
  20. c:/user/用户名目录创建文件名为.pypirc内容为:
  21. ```python
  22. [distutils]
  23. index-servers=pypi
  24. [pypi]
  25. repository=https://upload.pypi.org/legacy/
  26. username= 账户名
  27. password= 密码