第十三章:初识模块、包与开发目录规范
模块简介
1.模块的本质
内部具有一定的功能(代码)的 py 文件
2.python 模块的历史
python 刚开始的时候所有搞其他编程语言的程序员都看不起,甚至给 python 起了个外号>>>:调包侠(贬义词)
随着时间的发展项目的复杂度越来越高,上面那帮人也不得不用一下 python 然后发现真香定律>>>:调包侠(褒义词)
3.python 模块的表现形式
1.py 文件( py 文件也可以称之为是模块文件)
2.含有多个 py 文件的文件夹(按照模块功能的不同划分不同的文件夹存储)
3.已被编译为共享库或 DLL 的 c 或 C++ 扩展(了解)
4.使用 C 编写并链接到 python 解释器的内置模块(了解)
模块的分类
1.自定义模块
自己写的模块文件,如:调用另一个 py 文件
2.内置模块
python 解释器提供的模块,如:os、sys、time、datetime、json、shutil、logging ...
3.第三方模块
别人写的,并打包好的模块文件,需要时通常可通过:pip install pymysql 进行下载。
导入模块
模块导入的流程
1、先从 sys.modules 里查看是否已经被导入,即:模块不会被重复导入
2、如果没有被导入,就依据 sys.path 路径取寻找模块
3、找到了就导入
4、创建这个模块的命名空间
5、执行文件,把文件中的名字都放到命名空间里
import sys
print(sys.modules.keys())
print(sys.path)
模块导入的方式
import 导入整个模块,每次使用模块中的函数都要加模块名
from…import * 导入模块,每次使用模块中的函数,直接使用函数就可以了,但是容易跟执行文件中名字冲突
# 导入模块文件不需要填写后缀名,名称一般是纯英文,不会含有中文甚至空格
1.import句式,如:import datetime
1.先产生执行文件的名称空间
2.执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
3.在执行文件的名称空间中产生一个模块的名字
4.在执行文件中使用该模块名点的方式使用模块名称空间中所有的名字
2.from...import...句式,如:from collections import OrderedDict
1.先产生执行文件的名称空间
2.执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
3.在执行文件的名称空间中产生对应的名字绑定模块名称空间中对应的名字
4.在执行文件中直接使用名字就可以访问名称空间中对应的名字
3.from a import *
* 默认是将模块名称空间中所有的名字导入
4.form demo import * 与 __all__ = [''] 的关联使用
# 当使用这种模式调用模块时: form demo import * 与 __all__ = ['']
# 此时就只能调用 __all__ 对应列表中的函数
# demo.py
time = '20221019'
def reads():
pass
__all__ = ['times']
# run.py 主程序
from demo import * #__all__ = ['times']
print(times())
reads() #报错 NameError: name 'reads' is not defined
模块的别名
使用关键字 as 设置别名
import pandas as pd
from collections import OrderedDict as od
多个模块导入
如果模块功能相似度不高,推荐使用第一种
相似度高可以使用第二种
# 方法一
import os
import sys
import shutil
# 方法二
import os,sys,shutil
循环导入问题
两个文件之间彼此导入彼此,并且相互使用各自名称空间中的名字,极容易报错。
- 确保名字在使用之前就已经准备完毕
- 我们以后在编写代码的过程中应该尽可能避免出现循环导入(推荐)
循环导入的例子
get_py.py 主程序
import get_py2
name = 'ysg'
print(get_py2.name) # AttributeError: module 'get_py2' has no attribute 'name'
get_py2.py
import get_py
name = 'ysging'
print(get_py.name)
修复的例子
get_py.py 主程序
name = 'ysg'
import get_py2
print(get_py2.name)
get_py2.py
name = 'ysging'
import get_py
print(get_py.name)
输出结果:内存混乱造成的
ysging
ysg
ysging
绝对导入与相对导入
模块的导入全部以执行文件为准,相对导入使用频率较低 ,一般用绝对导入,这样结构更加清晰
绝对导入
from mymd.aaa.bbb.ccc.ddd import name # 可以精确到变量名
from mymd.aaa.bbb.ccc import ddd # 也可以精确到模块名
ps:套路就是按照项目根目录一层层往下查找
相对导入
.在路径中表示当前目录
..在路径中表示上一层目录
..\..在路径中表示上上一层目录
不在依据执行文件所在的 sys.path 而是以模块自身路径为准
from . import b
相对导入只能用于模块文件中,不能在执行文件中使用
判断文件类型
使用场景
1. 模块开发阶段
2. 项目启动文件
所有的 py 文件都可以直接打印 __name__ 对应的值
1.当 py 文件是执行文件的时候 __name__ 对应的值是 __main__
2.当 py 文件是被导入文件的时候 __name__ 对应的值是模块名
3.快捷方式为:main + 回车
if __name__ == '__main__':
run()
模块的查找顺序
当导入一个模块,Python 解释器对模块位置的搜索顺序是:
1.先从内存中找
2.再从内置模块中找
3.最后从 sys.path 中找(环境变量)一定要分清楚谁是执行文件谁是被导入文件,sys返回的是一个列表,里面放了一些文件的路径,但是第一个路径永远是文件所在的文件夹
注意:py文件的文件名不应该与模块名(内置的、第三方的)冲突,不然模块无此功能,会报错。
包
大白话:多个 py 文件的集合:文件夹
专业:内部含有 __init__.py 文件的文件夹 (python2必须要求 python3无所谓)
虽然 python3 对包的要求降低了 不需要 __init__.py 也可以识别,但是为了兼容性考虑最好还是加上 __init__.py
1.如果只想用包中某几个模块,那么还是按照之前的导入方式即可
from aaa import md1, md2
2.如果直接导入包名
import aaa
导入包名其实就是导包下面的 __init__.py 文件,该文件内有什么名字就可以通过包名点什么名字
软件开发目录规范
1.文件及目录的名字可以变换 但是思想是不变的 分类管理
2.目录规范主要规定开发程序的过程中针对不同的文件功能需要做不同的分类
myproject项目文件夹
1.bin文件夹 主要存放项目启动文件
start.py 启动文件可以放在bin目录下 也可以直接在项目根目录
2.conf文件夹 主要存放项目配置文件
settings.py 里面存放项目的默认配置 一般都是全大写
3.core文件夹 主要存放项目核心文件
src.py 里面存放项目核心功能
4.interface文件夹 主要存放项目接口文件
goods.py 根据具体业务逻辑划分对应的文件
user.py
account.py
5.db文件夹 主要存放项目相关数据
userinfo.txt
db_handler.py 存放数据库操作相关的代码
6.log文件夹 主要存放项目日志文件
log.log
7.lib文件夹 主要存放项目公共功能
common.py
8.readme文件 主要存放项目相关说明
9.requirements.txt文件 主要存放项目所需模块及版本