python全栈开发基础【第十二篇】Python的模块和包
一、模块
1.import....
一个py文件就可以作为一个模块
模块的导入:直接导入文件的名字,不需要带着后缀
模块中的函数调用:模块名.函数名()
导入模块的时候做了三件事:1.首先开辟了一个新的命名空间my_moudle
2.执行了my_moudle内的代码
3.将my_moudle里面的名字和命名空间绑定在一起了
注意:模块在一个程序中只会被导入一次,不会重复导入(为了节约资源)那么,如何实现模块在程序中只会被导入一次呢?(通过该特性可以实现单例模式)
当导入一个文件之后,会将模块存储在内存中,当再次导入的时候,就会到内存中查看是否导入过这个模块,如果已经导入过了,就不用再导入了。是通过sys里面的module方法
import sys for i in sys.modules: #查看是否导入过这个模块 print(i)
导入的模块有自己的命名空间(可以给导入的模块起一个别名,就产生了一个命名空间,这个命名空间只和别名相关)
import my_moudle as mm<br>print(mm.money)
# 别名 #mysql.py def sqlparse(): print('from mysql sqlparse') #oracle.py def sqlparse(): print('from oracle sqlparse') #test.py db_type=input('>>: ') if db_type == 'mysql': import mysql as db elif db_type == 'oracle': import oracle as db db.sqlparse()
2.from ...import...(也支持别名)
这种形式导入啥就能用啥,不导入的一律不能用
这个被import导入的名字就相当于属于全局变量了
from tmp import read1 read1() from tmp import read read()
参数问题和返回值问题都和函数一样(在哪返回在哪接收,在哪传参的在哪给参)
# from ...import... from zeze import read1 money = 1000 read1() # ------------------- from zeze import read2 def read1(): print('==========') read2() read1()
#测试:导入的函数read1,被当前位置定义的read1覆盖掉了 from zeze import read1 def read1(): print('==========') read1()
需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系,如下:
from zeze import money,read1 money=200#将当前位置的名字money绑定到了200 print(money)#打印当前的名字 read1()#读取zeze.py中的名字money,仍然为100
from...import *
*与all一起用的,首先会把模块中的所有不是‘_’开头的内容导入进来
可以通过__all__来控制导入的内容,但是只和*有关
*和__all__配合:__all__['read1','read2'],all里面导入什么,*里面就有什么,如果不用all,就都导入进来了。
# from my_moudle import * # from my_moudle import _money # print(read1) # print(read2) # print(_money) # print(read)
3.把模块当做脚本执行
#mytmp.py import mokuai print(mokuai.money) # 如果想让自己定义的模块,像和re模块的调用一样,执行的时候不显示什么,调用的时候才显示,为了 让tmp也一样不显示里面的内容,就在tmp模块里面判断一下 if __name__=='__main__': #tmp.py money = 100 def read1(): print('read1',money) return 'hello' def read2(): print('read2') if __name__=='__main__': read1() read2()
4.模块搜索路径
模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
lib里面放的是内置模块
扩展模块一般在site-packages中
sys.path:注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。
千万不要自己定义这些你熟悉的模块或关键字啊啥的作为自己的模块名
5.编译python文件
为了提高加载模块的速度,强调:提高的是加载速度而绝非运行速度。python解释器会在__pycache__目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。
1.以pyc为后缀的就为编译文件
2.编译pyc文件的时候,只有在导入文件的时候才做(就是作为一个模块的时候他才去编译)
二、包
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
强调:
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块
注意事项:
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者。
4.import
import glance.db.models glance.db.models.register_models('mysql')
5.__init__.py文件:
不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。
6.from glance .api import *
在讲模块时,我们已经讨论过了从一个模块内导入所有*,此处我们研究从一个包导入所有*。
此处是想从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:
7.绝对路径导入和相对路径导入
绝对路径:以glance作为起始
相对路径:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
相对路径只能在包中用(带上.或者..的在该模块下执行是报错的)
在glance/api/version.py #绝对导入 from glance.cmd import manage manage.main() #相对导入 from ..cmd import manage manage.main()
8.单独导入包