模块与包
模块
一个模块就是一个包含了一组功能的python文件,比如spam.py,模块名为spam,可以通过import spam使用。
模块的4种存在方式
1.使用c编写并链接到python解释器的内置模块
2.使用python编写的。py文件
3.包:一堆py文件集合体
q4.已被编译为共享库或dll的c或c++扩展
导入模块
1.编译执行模块所对应的py文件,形成对应的pyc文件
2.产生该模块自家的全局名称空间
3.在使用该模块的全局名称空间中产生一个名字(导入的模块名)
以spam.py为例来介绍模块的使用:文件名spam.py,模块名spam
#spam.py print('from the spam.py') money=1000 def read1(): print('spam模块:',money) def read2(): print('spam模块') read1() def change(): global money money=0
import
通过import关键字导入模块名
“import”是引入一个完整的模块,“from…import”是引入模块中的一个或多个指定部分;
“import”引入模块后,如果需要使用模块里的函数方法,则需要加上模块的限定名字,“from...import”则不用加模块的限定名字,直接使用其函数方法;
import module
编译执行模块所对应的py文件,形成对应的pyc文件
产生该模块自己的全局名称空间
在使用该模块的全局名称空间中产生一个名字(导入的模块名)
优点:
1.从文件级别组织代码,是同特性的功能能统一管理
2.可以使用系统或第三方模块(拿来主义),来提高开发效率
被导入模块有独立的名称空间
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突
#test.py import spam money=10 print(spam.money) ''' 执行结果: from the spam.py 1000 '''
为模块名起别名
为已经导入的模块起别名的方式对编写可扩展的代码很有用
1 import spam as sm 2 print(sm.money)
模块之from ... import...
from模块名 import*
导入的是模块中的_all_这个列表
1.系统默认该列表不会收录开头的名字
2.可以自定义_all_列表来规定外界通过*可以导入的名字
from 模块名 import 名字1,名字2,。。。,名字n
可以指名道姓导入模版中所有想导入的名字
测试一:导入的函数read1,执行时仍然回到spam.py中寻找全局变量money #test.py from spam import read1 money=1000 read1() ''' 执行结果: from the spam.py spam->read1->money 1000 ''' #测试二:导入的函数read2,执行时需要调用read1(),仍然回到spam.py中找read1() #test.py from spam import read2 def read1(): print('==========') read2() ''' 执行结果: from the spam.py spam->read2 calling read spam->read1->money 1000
py文件区分两种用途:模块与脚本
编写好的一个python文件可以有两种用途: 一:脚本,一个文件就是整个程序,用来被执行 二:模块,文件中存放着一堆功能,用来被导入使用
python为我们内置了全局变量__name__, 当文件被当做脚本执行时:__name__ 等于'__main__' 当文件被当做模块导入时:__name__等于模块名 #作用:用来控制.py文件在不同的应用场景下执行不同的逻辑 if __name__ == '__main__': 复制代码
logging 模块
logging模块是python提供的用于记录日志的模块
日志级别
在开始记录日志前还需要明确,日志的级别
随着时间的推移,日志记录会非常多,成千上万行,如何快速找到需要的日志记录这就成了问题
解决的方案就是 给日志划分级别
logging模块将日志分为了五个级别,从高到低分别是:
1.info 常规信息
2.debug 调试信息
3.warning 警告信息
4.error 错误信息
5.crtical 严重错误
本质上他们使用数字来表示级别的,从高到低分别是10,20,30,40,50
模块搜索路径
模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
模块的查找顺序 1、在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用 ps:python解释器在启动时会自动加载一些模块到内存中,可以使用sys.modules查看 2、如果没有,解释器则会查找同名的内建模块 3、如果还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件。
包
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。
包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来 随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
#文件内容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)
包的使用 import
1 import glance.db.models 2 glance.db.models.register_models('mysql')
包的使用之from ... import ...
需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
1 from glance.db import models 2 models.register_models('mysql') 3 4 from glance.db.models import register_models 5 register_models('mysql')
from glance.api import *
在讲模块时,我们已经讨论过了从一个模块内导入所有*,此处我们研究从一个包导入所有*。
#在__init__.py中定义 2 x=10 3 4 def func(): 5 print('from api.__init.py') 6 7 __all__=['x','func','policy']
绝对导入和相对导入
我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以glance作为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py
在glance/api/version.py 2 3 #绝对导入 4 from glance.cmd import manage 5 manage.main() 6 7 #相对导入 8 from ..cmd import manage 9 manage.main()
绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入 优点: 执行文件与被导入的模块中都可以使用 缺点: 所有导入都是以sys.path为起始点,导入麻烦 相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入 符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹 优点: 导入更加简单 缺点: 只能在导入包中的模块时才能使用