模块与包管理

模块

Copy
""" 常见的四种模块:module 1.使用python编写的.py文件 2.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包) 3.使用C编写并链接到python解释器的内置模块 4.已被编译为共享库或DLL的C或C++扩展 """ # 1、什么是模块:一系列功能的集合体,模块都有'.'语法 任何一个py文件或者说数据结构都能称为模块,因为都有'.'语法 # 2、为什么会出现模块:很多相似的功能,要统一管理,将这些功能放在一个文件中,该文件就是管理这些功能的集合体,我们命名为模块 # 3、怎么使用模块 # -- 在要使用模块功能的文件中导入模块: import 模块名 - 模块名:用来管理一系列功能的文件名(实现功能的文件名) # 4、在哪使用模块 # -- 在所有要使用模块中功能的文件中导入并使用模块 #模块文件(m1.py) def f1(): print('扫地') def f2(): print('洗衣') def f3(): print('拖地') # 使用模块文件 import m1 m1.f1() m1.f2() m1.f3()

导入模板完成的三件事

Copy
# 首次导入 import 模块名 # 1.将被导入的模块编译形成对应的pyc文件 # 2.进入模块,从上至下执行模块中的代码,将产生的所有名字(变量)存放在该模块文件的全局名称空间中 # 3.在使用模块的文件中,产生一个与模块名(模块文件名)同名的名字(变量),指向模块的全局名称空间,这个名字可以称为文件对象或者模块对象 #文件对象/模块对象 代表模块,指向的是模块文件里存储对象的名称空间的地址,通过使用'.'语法去使用模块里的东西 # 模块文件 m1.py print(1) print(2) print(3) a=10 def fn(): print(a) print('end') #使用模块的文件 import m1 print(m1.__dict__) #打印m1的名称空间 print(m1.__dict__['a']) #打印m1的名称空间 print(m1.a) # m1文件对象通过'.'语法去使用模块里的变量a print('t1 end') print(m1) #打印的是m1这个文件对象指向的模块的地址 # 再次导入 # 不再执行导入模块的前两步,只会走第三步:在当前模块中产生一个名字,指向第一次导入在内存中产生的全局名称空间 import m1 print(m1.a) print(m1.__dict__) #再次导入模块m1, m1的地址指向模块的名称空间

起别名

Copy
import 模块名 as 别名 # 重点:导入一旦起别名,原模块名变量失效,本质只产生了别名变量指向模块文件的全局名称空间

模块的分类

Copy
# 大方向:内置(built-in) | 自定义(系统提供 | 第三方提供 | 自己自定义)

模块的加载顺序

Copy
# 内存 > 内置 > sys.path (安装环境变量中路径的先后顺序逐一加载) # 自定义模块加载顺序: 根据环境变量中路径的顺序依次执行,加载到了就停止,所以排在前面的路径下的自定义模块先加载

环境变量

存放路径的list,第一位默认一定是当前执行文件所在的路径

Copy
#举例 >>> part4/t1.py import sys print(sys) print(sys.path) # ['/Users/cj/Desktop/pycharm_project_2/part4', '/Users/cj/Desktop/pycharm_project_2', '/Applications/PyCharm.app/Contents/helpers/pycharm_display', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Applications/PyCharm.app/Contents/helpers/pycharm_matplotlib_backend'] >>> part3/t1.py import sys print(sys) print(sys.path) # ['/Users/cj/Desktop/pycharm_project_2/part3', '/Users/cj/Desktop/pycharm_project_2', '/Applications/PyCharm.app/Contents/helpers/pycharm_display', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Applications/PyCharm.app/Contents/helpers/pycharm_matplotlib_backend']
Copy
import sys # sys.path就是环境变量 # 清空环境变量:所有导入都不能使用了 sys.path.clear() # 添加指定路径到环境变量 sys.path.append() sys.path.insert()

from...import语法导入

Copy
# 导入完成的三件事 # 1.将被导入的模块编译形成对应的pyc文件 # 2.进入模块,从上执行执行模块中的代码,将产生的所有名字存放在该模块文件的全局名称空间中 # 3.在导入模块的文件中形成(一个或多个)名字指向模块全局名称空间中的(一个或多个)具体名字 from 模块名 import 模块中的名字1, ..., 模块中的名字n from 模块名 import 名字 as 别名 # from...import导入依赖环境变量 sys.path #添加环境变量 import sys sys.path.append(r'/Users/cj/Desktop/pycharm_project_2/part2/t1.py')

from...import *

Copy
# 模块中默认会添加 __all__ ,__all__ 就是管理模块中能被 * 导入的变量们 # __all__可以自定义,自定义 * 能导入的变量们, __all__的list中名字全部可以自定义 __all__ = ['a', 'b', 'c', 'd_', '_e'] # 系统默认添加的__all__中不会纳入 _开头的名字 # -- 所以默认在外界通过from...import *无法导入_开头的名字 # -- _开头的名字对from...import *是隐藏的,指名道姓依然可以被外界导入使用 #m1.py _c=2 a=1000 #t1.py from m1 import * print(a) print(_c) #报错 NameError: name '_c' is not defined #m1.py _c=2 a=1000 #t1.py from m1 import _c print(_c) #输出c的值

链式导入

Copy
# t1导入m1,m1导入m2,m2导入m3 # 执行流程:右键执行t1,在t1导入m1模块的地方直接进入m1,去执行m1,同理在m1执行过程中遇到导入m2,会马上进入m2,去执行m2,一直到m3,m3执行完毕,会回到m2中导入m3的语句,接着往下执行m2,m2执行完毕回到m1,以此类推返回到t1 # 在整个执行流程中,遇到任何模块的二次导入,都是直接引用内存中的名称空间,不会再次进入模块
Copy
#t1.py print('t1 start') import m1 print('t1 end') #m1.py print('m1 start') import m2 print('m1 end') #m2.py print('m2 start') import m3 print('m2 end') #m3.py print('m3 start') import m1 import m2 print('m3 end')

循环导入

Copy
# 循环导入的问题点:名字没有产生就使用名字 # 解决循环导入:先产生名字,在导入模块 # -- 将会产生循环导入的模块,导入语法延后 - 延后导入 # 问题 #t1.py import m1 # m1.py import m2 print(m2.y) x=666 # m2.py import m1 print(m1.x) y=888 # 解决 #t1.py import m1 # m1.py x=666 import m2 print(m2.y) # m2.py import m1 y=888 print(m1.x)

sys.path显示

Copy
# 在pycharm中,sys.path环境变量这个列表索引0号位显示的是当前文件所在的路径,索引1号位显示的是pycharm中的项目的根目录 import sys print(sys.path[0]) # /Users/cj/Desktop/pycharm_project_3/part1/b/c print(sys.path[1]) # /Users/cj/Desktop/pycharm_project_3 # 但是在命令行界面,sys.path并不会显示项目的根目录 cj@cjwdeMacBook-Pro pycharm_project_3$ python3 /Users/cj/Desktop/pycharm_project_3/part1/t1.py ['/Users/cj/Desktop/pycharm_project_3/part1', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']

跨文件导入模块分析

Copy
# 需求:跨文件夹访问 #目录结构 part1 -> t1.py ->a(ma.py) ->b->c(mc.py) #打开pycharm时,当前执行文件的环境变量是会被自动创建为这个文件所在的目录,所以如果import 该文件所在的目录的任意模块文件都是可以的 #有时候我们要导入当前文件所在的目录的同级目录的模块文件,或者是同级目录以下的模块文件,这个时候可以将路径加入环境变量或者通过'.'语法进行层级导入,这本质上就是一个绝对路径,起始路径是从环境变量中定义的路径开始的,如果后面需要print输出这个值,那么后面也是要写除了环境变量定义的路径外的所有路径,这种情况定义别名更方便 (方法一) 绝对导入(将文件所在的目录的路径拷贝到环境变量sys.path) import sys # 访问模块文件ma里的变量aaa sys.path.append(r'/Users/cj/Desktop/pycharm_project_3/part1/a') import ma print(ma.aaa) # 访问模块文件mc里的变量ccc sys.path.append(r'/Users/cj/Desktop/pycharm_project_3/part1/b/c') import mc print(mc.ccc) 方法(二) 导入时写绝对路径 # 访问模块文件ma里的变量aaa import a.ma print(a.ma.aaa) # 访问模块文件mc里的变量ccc import b.c.mc print(b.c.mc.ccc) 方法(三)通过from...import 直接访问到模块里的变量,基于方法二 # 访问模块文件ma里的变量aaa from a.ma import aaa print(aaa) # 访问模块文件mc里的变量ccc from b.c.mc import ccc print(ccc) #报错信息 ('.'左侧为文件) import a.ma.aaa #语法错误 ModuleNotFoundError: No module named 'a.ma.aaa'; 'a.ma' is not a package #报错信息 ('.'左侧为文件) from b.c import mc.ccc as ccc #语法错误 SyntaxError: invalid syntax #结论: 导模块中的'.'语法左侧必须为文件夹 import 后面最后只能导入到文件,可以是import <文件夹>.<文件>,但是不能是import <文件>.<文件> from...import 中的import后面可以导入文件中的具体名字(变量名/函数名)

跨文件夹导入模块总结

Copy
# 1.如果a文件夹所在目录在环境变量,a文件夹中的ma模块可以被以下方式导入 import a.ma | from a import ma # 2.如果a文件夹所在目录在环境变量,a文件夹中的b文件夹的mb模块可以被以下方式导入 import a.b.mb | from a.b import mb # 3.如果a文件夹所在目录在环境变量,a文件夹中的b文件夹的mb模块中的bbb名字要被直接导入 import a.b.mb.bbb # 错误:所有.左侧必须是文件夹 ***** from a.b import mb.bbb # 错误:所有.左侧必须是文件夹 from a.b.mb import bbb # 正确

模块的两种被执行方式

Copy
# 总结: # 1.一个py文件作为自执行文件,__name__变量的值为 '__main__' # 2.一个py文件作为模块被导入执行,__name__变量的值为 '文件(模块)名' # 3. __name__的值始终是字符串 # 4. pycharm中直接输入main就能快速出现 if __name__ == '__main__': # 如何区别两种方式,可以让一个文件可以自执行,也可以被导入执行 共存 # 在这样的py文件中写: if __name__ == '__main__': # 自执行的逻辑 => 因为在文件作为模块使用时 __name__为文件名,不满足条件 pass #案例 fn3()函数所在的文件被外部调用时候不执行,外部调用时候只执行2个函数fn1(),fn2() # m1.py def fn1(): print('fn1 run') def fn2(): print('fn2 run') def fn3(): fn1() fn2() print('fn3 run') if __name__ == '__main__': fn3() #t1.py from m1 import fn1,fn2 fn1() fn2()

Copy
模块:一系列功能的集合体 包: 一系列模块的集合体,用文件夹来管理一系列有联系功能的模块 # 包 与 普通文件夹存在区别:包的文件夹中一定存在一个__init__.py文件 # -- py2:必须创建 py3:建议创建,不创建系统会自动创建 # __init__.py文件 # 1)产生一个全局名称空间,提供给包的,就代表包的名称空间 # 2)管理 包可以直接点出来使用的 名字 如果没有__init__文件,在py3中会自动优化生成一个名称空间,存储一些系统的内置变量,但是不会文件夹下面模块里定义的名字(变量名/函数名),py2中则直接报错 #(案例1) 文件结构: part5 >mp(m1.py/m2.py) >t1.py import mp #如果没有init文件, mp的名称空间是无法产生m1,m2模块以及他们的名字的对应关系 # 需求: 可以直接通过包名使用包中的某一个模块 print(mp.m1.a) print(mp.m1.b) print(mp.m1.c) # 需求: 可以直接通过包名使用包中的某个模块的名字 print(mp.x) print(mp.y) print(mp.z) # (案例2) 文件结构: part3 ->mp(m1.py, m2.py, m3.py) ->t1.py (python2 环境中) #t1.py import mp print mp 报错信息:ImportError: No module named mp (python3 环境中) import mp print(mp) <module 'mp' (namespace)> # mp自己的名称空间为空 print(mp.__dict__) # python3自动创建一个名称空间,都是系统内置的变量的对应关系 # 导包完成的三件事 # 1)编译形成包中__init__.py文件的pyc文件 # 2)执行__init__.py文件,形成一个全局名称空间,将__init__.py文件中所有名字存放其中,该名称空间就代表包的名称空间 # 3)在导包的文件中,产生一个与包名相同的名字,指向包的名称空间(__init__.py文件的全局名称空间)

相对导入

需求1 : 可以直接通过包名使用包中的某个模块的名字

Copy
文件结构: part3 ->mp(m1.py, m2.py, m3.py,__init__.py) ->t1.py (方法一) 直接将值存入__init__.py 文件 #t1.py # 可以直接通过包名使用包中的某个模块的名字 print(mp.x) print(mp.y) print(mp.z) # __init__.py x=111 y=222 z=333 (方法二) 将m1导入__init__.py 文件 #t1.py # 可以直接通过包名使用包中的某个模块的名字 import mp print(mp.m1.a) print(mp.m1.b) print(mp.m1.b) print(mp.m1.c) # __init__.py from . import m1 # '.'就是mp

需求2: 可以直接通过包名使用包中的某个模块的名字

Copy
#t1.py import mp # 导入一个绝对路径/Users/cj/Desktop/pycharm_project_3/part5/mp,所以__init__文件中可以使用相对路径,相当于__init__文件中再导入模块都是基于这个路径导入了 print(mp.x) print(mp.y) print(mp.z) # __init__.py from .m2 import x from .m2 import y from .m2 import z # '.'就是mp

需求3:直接通过包名使用包中子包模块中的名字

Copy
文件结构: part3 ->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py, __init__.py) ->t1.py # subp/s1.py sss=8888 #mp/__init__.py from .subp.s1 import sss from .subp import s1 #t1.py print(mp.sss) print(mp.s1.sss)

总结

Copy
1. mp是一个包,下面存着各个模块文件,运行文件中只要是导入了 import mp,则只要是__init__ 文件里面导入的模块,都能使用; __init__ 文件中导入模块可以使用相对路径,可以用'.'代替mp 2. import mp ----> 执行文件下相当于导入一个路径 /Users/cj/Desktop/pycharm_project_3/part5/mp 所以__init__文件中可以使用相对路径,相当于__init__文件中再导入模块都是基于这个路径导入了 3. from...import... 格式的文件,后面只能跟一个文件夹或者文件或者名字,不能跟多个字文件夹,文件,名字,用'.'分隔 from . import m1 #正确 from .m2 import x #正确 from .m2 import y #正确 from . import m2.z #错误

直接使用包中模块

Copy
# 如果只是想作为普通文件夹,py3中可以省略__init__文件,本质上文件夹也是包 # 导入的手段:1.指名道姓到某一个模块 | 2.指名道姓到某一个模块中的名字

包的管理

Copy
#在包中管理模块,或者模块与模块直接功能相互使用,通过from .开头 import 语法进行导入,这种导入叫相对导入 # 在包的__init__.py文件或是包中任意一个模块中 # . 代表当前文件所在目录 # .. 代表当前文件所在目录的上一级目录 # 注:.语法不能出包,因为包外的文件都能自执行,但拥有.开头导入的文件不能自执行
Copy
文件结构: part3 ->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py,s1.py,s3.py __init__.py) ->t1.py # subp/s1.py sss=8888 # subp/s2.py res=99999 # subp/s3.py from .s2 import res from ..subp.s1 import sss def fn(): # 要使用s2中的res print('s3 fn run') print(res) #要使用s1中的sss print(sss) #mp/__init__.py from .subp.s3 import fn # t1.py mp.fn()
Copy
# __name__ 代表路径 文件结构: part3 ->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py,s1.py,s3.py __init__.py) ->t1.py # subp/s1.py sss=8888 # subp/s2.py res=99999 # subp/s3.py from .s2 import res from ..subp.s1 import sss def fn(): # 要使用s2中的res print('s3 fn run') print(res) #要使用s1中的sss print(sss) # print(__name__) #mp/__init__.py from .subp.s3 import fn # t1.py mp.fn() # __name__ 最后的输出结果 mp.subp.s3

包管理的好处

Copy
包管理内部采用相对导入管理模块或者模块中的名字(变量/函数名),外部调用模块的文件采用绝对导入导入一个包名,实际上导入的是路径,这样做的好处是复用性高,外界想要使用包中的模块只要导入包的路径,接下来都不用修改内部代码
posted @   cjw1219  阅读(139)  评论(0编辑  收藏  举报
编辑推荐:
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
阅读排行:
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· mysql8.0无备份通过idb文件恢复数据过程、idb文件修复和tablespace id不一致处
· 使用 Dify + LLM 构建精确任务处理应用
点击右上角即可分享
微信分享提示