模块
模块:一系列功能的集合体
模块的三种来源:
1.内置的
2.自定义的
3.第三方的
四种表现形式:
1 使用python编写的.py文件(一个py.文件也可以称之为一个模块)
2 已被编译为共享库或DLL的C或C++扩展
3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4 使用C编写并链接到python解释器的内置模块
包:一系列py.文件的结合体.
1.用别人写好的模块(内置的,第三方的):典型的拿来主义,极大地提高开发效率.
2.使用自己写的模块(自定义):当程序大,多文件都需要相同的方法时,可以将公共的方法都写在一个py.文件中,当做模块导入
解耦合
区分执行文件和被导入文件
import导入模块
md.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('from the md.py') money = 1000 def read1(): print('md',money) def read2(): print('md模块') read1() def change(): global money money = 0
run.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import md
右键运行run.py文件首先会创建一个run.py的名称空间
首次导入模块(md.py)
1.执行md.py文件
2.运行md.py文件中的代码将产生的名字与值存放到md.py名称空间中.
3.在执行文件中产生一个执行名称空间的名字(md)
多次导入不会再执行模块文件,会沿用第一次导入的结果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
访问模块中的名字指向的值 print(md.money) #得到了值 模块名.名字 print(md.read1) print(md.read2) print(md.change) #均得到了函数的地址
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import md money = 9999 print(money) #得到了当前执行文件的值 def read1(): print('from run read1') read1() #得到当前文件的值
1.只要你能拿到函数名 无论在哪都可以通过函数加括号来调用这个函数(会回到函数定义阶段 依次执行代码)
2.函数在定义阶段 名字查找就已经固定了 不会因为调用位置的变化而改变
使用import导入模块,访问模块名称空间中的名字统一句式:模块名.名字 1.指名道姓的访问模块中的名字 永远不会与执行文件中的名字冲突 2.你如果想访问模块中名字 必须用模块名.名字的方式
import os,sys
当几个模块有相同部分或者属于用一个模块,可以使用上面的方法,一行导入多个模块
当几个模块没有联系的情况下 应该分多次导入
import os
import time
import md
ps:通常导入模块的句式会写在文件的开头
取别名
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import aaaaaaaaaa.py as a 当模块名字比较复杂的情况下 可以给该模块名取别名
异常
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
while True: try: print(d.__next__()) print(name) sdfsdfj except Exception: break name = "bobob" 异常有两大类 1.语法结构错误:需要你当场修改 异常捕获没法完成 2.逻辑错误:异常捕获可以处理
md1.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('from the md1.py') money = 1000 def read1(): print('md',money) def read2(): print('md模块') read1() def change(): global money money = 0 __all__ = ['money','read1','read2']
run1.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from md1 import money,read1,read2,change
会先创建run1.py的名称空间
首次导入md1.py模块
1.运行md1.py
2.将产生的名字存放到md1.py名称空间中
3.直接拿到指向模块md1.py名称空间中某个值的名字
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
导入完成的三件事 1. 将被导入的模块编译形成对应的pyc文件 2. 进入模块,从上执行执行模块中的代码,将产生的所有名字存放在该模块文件的全局名称空间中 3. 在导入模块的文件中形成(一个或多个) 名字指向模块全局名称空间中的(一个或多个) 具体名字 from 模块名 import 模块中的名字1, ..., 模块中的名字n from 模块名 import 名字 as 别名 from ...import导入依赖环境变量 sys.path
利用from...import...句式
缺点:
1.访问模块中的名字不需要加模块名前缀
2.在访问模块中的名字可能会与当前执行文件中的名字冲突
优点
1.省略了点语法 2.指名道姓可读性强 3.可以起别名解决冲突
from md1 import * # 一次性将md1模块中的名字全部加载过来 模块中默认会添加 __all__ ,__all__ 就是管理模块中能被 * 导入的变量们 __all__可以自定义,自定义 * 能导入的变量们, __all__的list中名字全部可以自定义 系统默认添加的__all__中不会纳入 __开头的名字 -- 所以默认在外界通过from...import *无法导入_开头的名字 -- _开头的名字对from...import *是隐藏的,指名道姓依然可以被外界导入使用 __all__可以指定当所在py文件被当做模块导入的时候 可以限制导入者能够拿到的名字个数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import m1 m1.f1()
m1.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('正在导入m1') from m2 import y # 首次导入m2 x = 'm1'
m2.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('正在导入m2') from m1 import x # 第二次导m3 y = 'm2'
打印结果 正在导入m1 正在导入m2 如果出现循环导入问题 那么一定是你的程序设计的不合理 循环导入问题应该在程序设计阶段就应该避免 解决循环导入问题的方式 1.方式1 将循环导入的句式写在文件最下方() 2.方式2 函数内导入模块
解决:
m1.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
方式1 print('正在导入m1') x = 'm1' from m2 import y # 首次导入m2 print('正在导入m1') def f1(): from dir1.dir.m2 import y,f2 print('m1.f1>>>y:',y) f2() x = 'm1'
m2.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
方式1 print('正在导入m2') y = 'm2' from m1 import x # 第二次导m print('正在导入m2') def f2(): from dir1.dir.m1 import x print('m2.f2>>>x:',x) y = 'm2'
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import m1 m1.f1()
m1.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('正在导入m1') from m2 import y # 首次导入m2 x = 'm1'
m2.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print('正在导入m2') y = 'm2'
t1导入m1,m1导入m2,m2导入m3 执行流程:右键执行t1,在t1导入m1模块的地方直接进入m1,去执行m1,同理在m1执行过程中遇到导入m2,会马上进入m2,去执行m2,一直到m3,m3执行完毕,会回到m2中导入m3的语句,接着往下执行m2,m2执行完毕回到m1,以此类推返回到t1 在整个执行流程中,遇到任何模块的二次导入,都是直接引用内存中的名称空间,不会再次进入模块
def index1(): print('index1') def index2(): print('index2') print(__name__) 区分执行文件和被导入文件 # 当文件被当做执行文件执行的时候__name__打印的结果是__main__ # 当文件被当做模块导入的时候__name__打印的结果是模块名(没有后缀) if __name__ == '__main__': index1() index2() if __name__ == '__main__': # 快捷写法 main直接tab键即可 index1() index2()
1.先从内存中找 2.内置中找 3.sys.path中找(环境变量): 内置(built-in): 自定义(系统提供|第三方提供|自定义) 加载顺序: 内置>sys.path(安装环境变量中路径的先后顺序逐一加载)
import sys print(sys) 是一个大列表,里面放了一对文件路径,第一个路径永远是执行文件所在的文件夹 注意py文件名不应该与模块名(内置的,第三方)冲突
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
.代表的当前路径
..代表的上一级路径
...代表的是上上一级路径
注意相对导入不能在执行文件中使用
相对导入只能在被导入的模块中使用,使用相对导入 就不需要考虑
执行文件到底是谁 只需要知道模块与模块之间路径关系
绝对导入必须依据执行文件所在的文件夹路径为准 1.绝对导入无论在执行文件中还是被导入文件都适用
环境变量:存放路径的list sys.path就是环境变量 默认为当前执行文件所在的路径 清空环境变量:所有导入都不能使用 sys.path.clear() 添加指定路径到环境变量 sys.path.append() sys.path.insert()
如;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) if __name__ == '__main__': src.run()
bin start.py 启动文件 conf settings.py 配置文件 core src.py 核心代码文件 lib common.py 公共文件 db 数据文件 log logging 日志记录文件 readme 项目说明简介