2018.08.03 (模块和包)
一.模块的理论知识
1.模块的分类
(1)内置模块 (安装python解释器的时候跟着安装上的那些方法)
(2)第三方模块/扩展模块 (没在安装python解释器的时候安装的那些功能)
(3)自定义模块 (程序员自己写的功能如果是一个通用的功能,那就可以把它当做一个模块)
2.什么是模块?
(1)有的功能开发者自己无法完成,这样的话需要借助已经实现的函数/类来完成这些功能
(2)比如你实现不了的功能都由别人替你实现了
(3)模块就是别人写好的一组功能,这组功能是以文件夹的形式或者py文件的形式,或者是c语言编译好的一些编译文件的形式存储
(4)模块的好处就是:(1)分类管理方法(2)节省内存(3)提供更多的功能
3.为什么要有模块?
(1)分类管理方法
(2)节省内存
(3)提供更多的功能
(4)功能可以重复利用
二.常用模块
1.import 文件名(模块名)
(1)该模块的创建和导入
①自己创建一个命名为my_module的py文件,里面可以存放模块以及功能 (模块名必须满足变量的命名规范,一般情况下.模块都是小写字母开头的)
②在要导入模块的文件里 ===> import my_module (导入一个py文件的文件名,但是不加.py的后缀)
import my_mudule ===>当import这个模块的时候就相当于执行了这个模块所在的py文件
(2)该模块可以被重复导入么?
一个模块不会被重复导入
(3)如何使用该模块?
import 文件名的时候发生了什么?
①找到这个my_module模块
②创建一个属于my_module的内存空间
③执行my_module
④将这模块所在的命名空间建立一个和my_module之间的引用关系
(4)该模块的重命名 (修改的是引用的变量名,模块名并没有被改变)
import my_module as m
m.login() (引用的变量名改变,就需要拿修改过后的变量名进行调用)
my_module.login() (引用的变量名改过之后,就不能再拿以前的变量名进行调用)
(5)导入多个模块
① 一行导入多个模块(不建议使用) import os,my_module
② 多行导入多个模块 import os\n import my_module
导入多个模块必须遵循PEP8规范====>必须一行一行导入模块
所有的模块导入都应该尽量放在这个文件的开头
多个模块导入的顺序:内置模块 ---->第三方模块/扩展模块 ----> 自定义模块
多个模块导入的好处:方便其它人看你导入了哪些模块
2.from (模块名) import (方法名/属性)
当在pycharm中导入from 模块名 import 方法名/属性 的时候,可能会报错,如果报错,不是python解释器发现的错误,而是pycharm根据它自己的一些判断而得出的结论
可以通过:copy path 该文件的地址,重新open打开, 粘贴copy过来的地址,在新的窗口里打开
(1)from ... import ... 的时候发生了什么?
from ... import ... 的时候就相当于执行了整个模块的文件,并将模块里的全部信息加载一遍
①执行到from my_module 发生了什么?
首先找到my_module模块
然后开辟一块属于这个模块的命名空间
执行这个模块,将模块里面的全部内容加载一遍
②执行到import login 发生了什么?
知道了要import的是login这个名字,那么就会在当前执行的模块的文件里创建一个login的变量,然后这个变量login会指向模块命名空间中的login方法
(2)在from ... import ... 的时候命名空间的交换
import导入了什么.就能使用什么,不导入的方法或者属性,就不能使用
但是不导入并不意味着不存储,而是没有建立文件到该模块中其他方法/属性名字的引用
例如:
from_import.py文件 my_module.py
from my_module import login print("饿了么")
login() ====> "饿了么" "login",egon name = "alex"
def login():
print("login",name)
name = "egon"
例如:
如果自己文件中也有login()函数的时候,会先执行自己空间里的login()函数
from my_module import login
def login():
print("in my login") ====>in my login
例如:
from my_module import login
def login():
print("in my login") ====>in my login
from my_module import login
login() =====>login egon
当模块中导入的方法或者变量和本文件方法或变量重名的时候,那么这个名字只代表最后一次对它赋值的那个方法或者变量
在本文件中对全局变量的修改是完全不会影响到模块中的变量引用的
(3)该模块的重命名
form my_module import login as l
l()
该重命名跟import模块的重命名规则一样
导入多个重命名
from my_module import login as l ,name as n
(4)导入多个模块
例如:
from my_module import login,name
login() ===> login egon
print(name) ===>egon
name = "太亮"
login() ===>login egon
print(name) ===>"太亮"
(5)from ... import *
模块中的所有方法/变量都能引用
(6)__all__可以控制*导入的内容(只能控制*)
__all__["login","name"] 可以导入login和name
__all__["login"] 只能导入login,调用模块中的login,name没有导入,所以不能调用
三.模块相关的其它知识
1.把模块当成脚本运行
(1)运行py文件的两种方式:
①以模块的形式进行 (import my_module)
②直接右键运行/直接pycharm运行/cmd运行 (以脚本的形式进行)
如果直接自己文件中执行文件 print(__name__) ===>"__main__"
以模块形式,如果不是直接在自己文件中执行 print(__name__) 打印出来的是调用的模块的名字
如果想要以脚本的形式执行,那么需要在本文件中直接打印的代码上加上 if__name__ == "__main__"
在编写py文件的时候:
所有不在函数和类中封装的内容都应该写在 if __name__ == "__main__"的下面 (所有不需要调用就能执行的代码)
打印 if __name__ == "__main__" 的快捷键 main+Teb键
import sys
import my_module
sys.modules ===>{"sys":"文件的内存地址","my_module":"my_module的内存地址","__main__":"当前直接文件所在的地址"}
存储了所有导入的文件的名字和这个文件的内存地址
在使用反射自己模块中的内容的时候
import sys
sys.modules[__name__]
getattr(sys.modules[__name__],变量名) 这句话写在哪个文件,就代表哪个文件的命名空间
2.模块搜索路径
import sys
print(sys.path) ===> 一个模块能不能被导入,就看sys.path中是否有这个模块所在的绝对路径
总结:
模块的搜索路径全部存储在sys.path列表中,导入模块的顺序,是从前到后找到一个符合条件的模块就立即停止,不再向后寻找,如果要导入的模块和当前执行的文件同级,直接导入即可.
如果要导入的模块和当前执行的文件不同级,需要把到导入模块的绝对路径添加到sys.path列表中
报错提醒:ModuleNotFoundError:No module named ====>(说明sys.path出错)
3.pyc编译文件
import aa 模块导入的时候
python执行的时候,是一个解释/编译的过程(自动编译),当一个文件作为一个脚本被导入的时候,就会在这个文件所在的目录的__pycache__下生成一个编译好的文件,为了之后导入这个文件的时候直接读这个编译好的pyc文件就可以了,能够节省一些导入的时间
4.重新加载文件 (已经导入的模块即便被修改,在程序执行的过程中也不会生效)
import aaa
import time
import importlib
aaa.login()
time.sleep(20) ===>缓冲20秒在打印
importlib.reload(aaa) 表示重新加载
aaa.login
在import之后,在修改这个被导入的模块,程序是感知不到的
5.模块的循环引用
在模块导入中,不要产生循环引用的问题
如果发生循环导入了,就会发现明明写在这个模块中的方法却显示找不到了
四.包
1.什么是包?
集合了一组py文件,提供了一组复杂功能的py文件
包是目录级的(文件夹级的),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件目录)
2.为什么要有包?
当提供的功能比较复杂的时候,一个py文件写不下的时候
3.包中有什么?
至少有一个__init__.py
4.简单的导入 (从包中导入模块,要注意这个包所在的目录是否在sys.path列表中,导入的包的开始的 包也必须在sys.path中)
(1)import 包.包....模块
调用: 包.包... .模块
main.login()
(2)from 包.包.... import 模块
5.导入包 ===相当于执行这个包下面的__init__.py
import glance (设计一下init文件来完成一些模块的导入)
如果是直接导入一个包,那么相当于执行了这个包中的__init__文件,并不会帮你把这个包下面的其它包以及py文件自动的导入到内存,如果你希望直接导入包后,所有的这个包下面的其它包以及py文件都能直接通过包来引用,那么你要自己处理__init__文件(倒入设置)
6.绝对导入和相对导入
首先glance是最顶级的包
glance/api/version.py
绝对路径:
from glance.cmd import manage
manage,main()
相对导入:
from .. cmd import manage
manage.main()