python-模块和包
1、模块化程序设计理念
1.1模块和包概念的进化史
量变引起质变是哲学中的一个重要的理论。量变为什么会引起质变?本质上理解,随着数量的增加,管理方式会发生本质的变化;旧的管理方式完全不适合,必须采取新的管理方式。
程序越来越复杂,语句多了,怎么管理?很自然的,我们会将实现同一个功能的语句封装到函数中,统一管理和调用,于是函数诞生了。
程序更加复杂,函数和变量多了,怎么管理?同样的思路,物以类聚,我们将同一类型对象的数据和行为,也就是变量和函数,放到一起统一管理和调用,于是类和对象诞生了。 程序继续复杂,函数和类更加多了,怎么办?好,我们将实现类似功能的函数和类统统放到一个模块中,于是模块诞生了
程序继续复杂,模块多了怎么办?于是,我们将实现类似功能的模块放到一起,于是包就诞生了。
大家可以清晰的看到这发展的流程,核心的哲学思想就是量变引起质变、物以类聚。同样的思路,在企业管理、人的管理中思路完全一致。大家可以举一反三。
1、python程序由模块组成,一个模块对应python源文件,一般后缀名是:.py
2、模块由语句组成。运行python程序时,按照模块中语句的顺序依次执行
3、语句python程序的构造单元,用于创建对象、变量赋值、调用函数、控制语句等
1.2标准库模块
与函数类型,模块也分为标准库模块和用户自定义模块
Python标准库提供了操作系统功能、网络同喜、文本处理、文件处理、数学运算等基本的功能。比如:random、math、time、file、os、sys
另外python还提供了海量的第三方模块,使用方式和标准库类似。功能覆盖了我们能想象到的所有领域,比如:科学计算、web开发、大数据、人工智能、图形系统等等。
1.3为什么需要模块化
模块对应于python源代码文件。模块中可以定义变量、函数类、普通语句。这样,我们可以将一个python程序分解成多个模块,便于后期的重复应用。
模块化编程将一个任务分解成多个模块。每个模块就像一个积木一样,便于后期的反复使用、反复搭建。
优势如下:
1、便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
2、实现代码复用。一个模块实现后,可以被反复调用
3、可维护性增强
1.4模块化编程的流程
模块化编程的一般流程:
1、设计API,进行功能描述
2、编码实现API中描述的功能
3、在模块中编写测试代码,并消除全局代码
4、使用私有函数实现不被外部客户端调用的模块函数
1.5模块的API和功能描述要点
API(application programming interface)是用于描述模块中提供的函数和类的功能描述和使用方式描述。
模块化编程中,首先设计的就是模块的API,然后开始编码实现API描述的功能和使用方式描述。模块化编程,首先设计的就是模块的API,然后开始编码实现API描述的功能。最后,在其他模块中导入本模块进行调用。
我们可以通过help查看模块的API
2 模块的导入
Import语句本质上就是调用内函数
import test02
import test02
#3.141592653589793 导入两次只打印了一次
print("-----")
import importlib
importlib.reload(test02)#重新导入的方法
3 包package的使用
3.1 包的概念和结构
当一个项目中有很多个模块时,需要再进行组织。我们将功能类似的模块放到一起形成了了包,本质上,包就是一个必须有__init__.py的文件夹。典型结构如下
包下面可以包含模块,也可以再包含子包。就像文件夹下面可以有文件,也可以有子文件夹一样。上图中,a是上层的包,下面有一个子包:aa.可以看到每个包里面都有__init__.py
的
3.2 创建包
创建b包
创建A包
3.3 导入包操作和本质
上一节中的包结构,我们需要导入module_AA.py。方式如下:
1、import a.aa.module_AA
在使用时,必须加完整名称来引用,比如:a.aa.module_AA.fun_AA()
2、from a.aa import module_AA
在使用时,直接可以使用模块名。比如:module_AA.fun_AA()
3、from a.aa.module_AA import fun_AA 直接导入函数
在使用时,直接可以使用函数名。比如:fun_AA()
[注] 1、from package import item 这种语法中,item可以是包、模块,也可以是函数、类、变量
2、import item1.item2 这种语法中,item必须是包或模块,不能是其他
导入包的本质其实是“导入了包的__init__.py”文件。也就是说,“import_pack1”意味
#import a.aa.module_AA
#a.aa.module_AA.funAA()
#from a.aa import module_AA
#module_AA.funAA()
import a
print(a.math.pi)
import math
print(id(math))
print(id(a.math))
#导入A包
#3.141592653589793
#2291742604728
#2291742604728 地址一样 所以模块一样
导入包的本质其实是“导入了包的__init__.py”。也就是说,“import pack1”意味着执行了包pack1下面的__init__.py文件。这样可以在__init__.py中批量导入我们需要的模块,而不再需要一个个导入。
init.py的三个核心作用:
1、作为包的标识,不能删除
2、用来实现模糊导入
3、导入包实质是执行__init__.py文件,可以在__init__.py文件中做这个包的初始化,以及需要统一执行代码
3.4 模糊导入 用*导入包
Import* 这样的语句理论上是希望文件系统找出包中所有的子模块,然后导入他们。这可能会花长时间等。Python解决方案是提供一个明确的包索引。
这个索引由__init__.py定义__all__变量,该变量为一列表,如上例子中a包下的__init__.py中,可定义__all__=[“module_A”,”module_A2”]
这意味着,from sound.effects import * 会从对应的包中导入以上两个子模块:
【注】尽管使用import*的方法,仍不建议在生产代码中使用这种写法
print(“导入A包”)
all=[“module_A”,“module_A2”]
from a import *
module_A2.funA2()
module_A.funA()
#module_A3 报错
3.5 包内引用
如果是子包内的引用,可以按相对位置引入子模块,以aa包下的module_AA中导入a包下内容为例:
From … import module_A # … 表示上级目录 . 表示同级目录
from …a.aa import module_AA
From . import module_A2 #. 表示同级目录
from . import module_B1
3.6 sys.path 和模块搜索路径
当我们导入某个模块文件时,python解释器去哪里找这个文件呢?只有找到这个文件才能读取、装在运行该模块文件。它一般按照如下路径寻找模块文件(按照顺序寻找,找到即停不继续往下寻找):
1、内置模块
2、当前目录
3、程序的主目录
4、Pythonpath目录(如果设置了pythonpath环境变量)
5、标准链接库目录
6、第三方库目录
7、.pth文件的内容
8、Sys.path.append()临时添加的目录
当任何一个python程序启动时,就将上面的这些搜索路径(除内置模块以为的路径)进行收集,放到sys模块的path属性中(sys.path)。
4 模块发布和安装
4.1 模块的本地发布
当我们完成了某个模块开发后,可以将他对外发布,其他开发者也可以以“第三方扩展库”的方式使用我们的模块,我们按照如下步骤即可实现模块的发布
1 为模块文件创建如下解雇的文件夹(一般,文件夹的名字和模块的名字一样):
2 在文件夹中创建一个名为setup.py的文件,内容如下
from distutils.core import setup
setup(
name=‘baizhanMath2’,#模块名
version = ‘1.0’,#版本
description=“这是第一个对外发布的模块,测试哦”,#描述
author = “zzh”,
author_email = “xxx@qq.com”,#邮箱
py_modules = [‘baizhanMath2.demo1’,‘baizhanMath2.demo2’]#要发布的模块
)
3 构建一个发布文件。通过终端,cd到模块文件夹c下面,再键入命令:
Python setup.py sdist
执行完毕后,目录结构为:
4.2 本地安装模块
安装该包,点击setup.py open in terminal
python setup.py install --prefix=/path/to/install # 等号后面写安装路径