模块和包
模块: 什么是模块?
1. .py 文件
2. c语言编译之后的文件:写好的代码集合,直接调用他的功能.
为什么要有模块?
内存空间是有限的,存放在硬盘里.当需要的时候加载到内存,把丰富的功能封装在一个文件里.等用的时候直接导入内存就可以使用.
有哪些种类的模块?
1.内置模块 : re time sys os
2.扩展模块(第三方): django pip3 install
3.自定义模块:
模块: 功能独立, 防止代码过长.
自定义模块:
自定义模块的创建,导入,模块名
注意模块名需要符合变量命名规范.
导入模块的时候,pycharm的报错提示是不可靠的.
导入一个模块就是import 文件名 不带 .py
模块的命名空间:
每一个模块的导入都会创建一个属于自己的命名空间.
1.模块导入的过程到底做了哪些事?
1,创建一个属于这个模块的命名空间
2.执行这个模块中的代码
3.创建一个应用来调用这个模块命名空间中的名字.
4.把导入的模块和内存地址存到sys.modules中
2.这个模块会被重复导入吗?
这个模块不会被重复导入
import sys
import my_module
print(sys.modules)
print(sys.modules["my_module"])
print(my_module)
内存中所有被导入的模块都会存储在sys.modules字典中.这个字典的key就是这个模块的名字,value是这个模块的内存地址.
模块导入之后,可以直接使用这个模块中的函数和变量
print(my_module.flag)
my_module.read1()
my_module.read2()
import my_module as m
可以给导入的模块进行重命名,重命名之后新的名字会出现在内存空间中来作为模块的引用.但是原模块名就不内阁在文件中使用了. 用处:1.模块名太长. 2.方法名都一样,(下面举个栗子)
例:序列化: json pickle 提供序列化功能,帮助用户对***进行序列化
def dump(somthing , m = "json"):
if m == "json" : import json as m
else: import pickle as m
m.dumps(somthing)
导入多个模块:
1.都写在文件的开始.
2.顺序:先导入内置的,再导入扩展的,最后导入自定义的.
import os
import sys
import flash #扩展的web框架
import requests #请求url
import my_module
导入多个模块:
import os as o , sys as s, flask as f
from import
模块的命名空间.
在导入模块的时候发生了什么?
只导入模块中的某一个名字,其他没有导入的不能直接使用
为模块起别名 as
导入多个名字:
可以from 模块 import 名字1,名字2
也可以from 模块 import * #一般情况下不用.
import my_module
导入这个模块,相当于执行一个模块
导入模块,模块名作为这个模块命名空间的一个引用
可以使用模块名随意地使用这个命名空间中的名字.
from my_module import flag
from import 仍然会在导入模块的时候执行整个模块
仍然会把模块中所有的名字存在一个属于这个模块的命名空间中.
区别在于:实用模块中名字的时候不需要再带着模块名,而是导入了什么名字,就是用什么名字.没有导入的名字不能使用.
flag = False
print(flag)
read2() #不能使用,会报错
my_module.read1() #不能使用,会报错
import 和 from import都会完整的执行这个my_module文件,在from import没有被导入的其他名字就不能用了.
导入多个名字和重命名语法
from my_module import flag as f, read1 as r
print(f)
from my_module import * == from my_module import flag,read1,read2
print(flag)
read1()
如果导入一个模块,这个模块中假设有20个方法,只用一个,用from 模块 import 这个方法.
如果需要用10个 用import 模块 这个方法
* 和 __all__(__all__只和 * 相关)
如果不定义__all__,默认*可以导入这个模块中的所有名字.
如果定义了__all__,那么只有出现在all这个列表中的名字可以被 * 导入.
模块的循环引用:一定会报错,只要涉及到文件的导入,永远不能成循环,否则会报错
模块的加载与修改(了解)
import importlib
import.reload(模块名)
上面是模块的修改.只有测试的时候使用,正式代码不用.
例:
import time
import importlib
import my_module
print(my_module.flag)
time.sleep(20)
importlib.reload(my_module) #测试
print(my_module.flag)
把模块当做脚本来执行(*****)
if __name__ == "__main__":下面的代码只有在直接执行这个文件的时候才被执行.
from my_module import login
__name__ 是py文件中的一个内置的变量.
当直接执行这个py文件的时候,这个文件中的__name__就是"__main__",当以模块的形式导入这个py文件的时候,这个文件中的__name__就是模块名的字符串.
if __name__ == "main":
写在这段代码下面的所有内容只有在当前稳健被直接run的时候才会执行 . 被导入的时候不会被执行,
脚本 : 就是一个被直接执行run的文件.
模块搜索路径:
import sys
print(sys.path)
第一个元素是当前执行的.py文件所在目录.所以同目录下的py文件的导入 都不会报错.如果要导入的文件不是同目录下的,需要修改sys.path目录.
import sys
print(sys.path)
导入模块的时候,从这个列表中的目录下去找
sys.path.append(r"要导入的文件目录")
import core
core.login()
包 : 导入模块常用的两种方法
import
from import
导入包:
__init__文件,在导入包的时候执行这个包下的__init__方法.
绝对导入:永远要注意路径的问题.
相对导入:永远不要直接执行使用了相对导入的文件
__all__ 和* :也不是完美的,但是可以简化操作.
例: 在policy 文件中用get方法,要使用get方法,得先导入policy.
import glance .api.policy #只能也必须精确到模块
glance.api.policy.get()
import glance .api.policy as policy #也只能必须精确到模块
policy.get()
from glance.api import policy(这个位置不能有点)
policy.get() #凡是在导入时带点的,点的左边都必须是一个包.
如果导入的是一个包的名字而不是一个py文件的名字,就会直接执行这个包下面的__init__.py,除此之外什么也不会做.
import sys
print(sys.path)
import glance #glance文件下有api文件夹,api文件夹中有policy文件
glance.api,policy.get()
import glance
使用相对导入,不能直接执行使用了相对导入的文件;必须将这个存在着相对导入的包作为一个整体来使用.
只写了一个包,这个包对外提供功能,而不是用来直接执行这个包中的某个py文件的时候才会用到相对导入.
软件的开发规范(*********必须了解)