模块和包
1.什么是模块
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀
其实import加载的模块分别为死歌通用类别:
1.使用pytho编写的代码(.py文件)
2.已被编译为共享库或DLL的C或C++扩展
3.包好一组模块的包
4.使用C编写并链接到python解释器的内置模块
2.如何自己写一个模块
创建一个py文件,给它起一个符合变量命名规则的名字,这个名字就是模块名
3.模块的导入
导入一个模块就是执行一个模块
模块导入的过程中发生了什么:
1.找到这个模块
2.判断这个模块是否被导入过了
3.如果没有被导入过:
创建一个属于这个模块的命名空间
让模块的名字指向这个空间
执行这个模块中的代码
给模块起别名:起了别名之后,就只能使用这个模块的别名引用变量了
导入多个模块:
import os,time
规范建议:
模块应该一个一个的导入:
内置模块
扩展(第三方)模块
自定义模块
from import
模块导入的过程中发生了什么:
1.找到要被导入的模块
2.判断这个模块是否被导入过
3.如果这个模块没被导入过
创建一个属于这个模块的命名空间
执行这个文件
找到要导入的变量
给导入的变量创建一个引用,指向要导入的变量
1 #测试一:导入的函数read1,执行时仍然回到my_module.py中寻找全局变量money 2 #demo.py 3 from my_module import read1 4 money = 1000 5 read1() 6 7 #测试二:导入的函数read2,执行时需要调用read1(),仍然回到my_module.py中找read1() 8 #demp.py 9 from my_module import read2() 10 def read1(): 11 print("1") 12 read2()
如果当前有重名read1或者read2,那么会有覆盖效果
1 #测试三:导入的函数read1,被当前位置定义的read1覆盖掉了 2 #demo.py 3 from my_module import read1 4 def read1(): 5 print("1") 6 read1() 7 执行结果: 8 from the my_module.py 9 1
from my_module import *把my_module中所有的不是以下划线(_)开头的名字都导入到当前位置
from my_module import * print(money) print(read1) print(read2) 执行结果: from the my_module.py 1000
如果my_module.py中的名字前加_,即_money,则frommy_module import *,_money不能被导入
模块引用中的情况:模块之间不允许循环引用
4.模块的加载与修改
每个模块只被导入一次,放入到sys.modules中,如果改变了模块中的内容,必须重启程序
5.把模块当成脚本来使用
可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__等于'__main__'
当做模块导入:
__name = 模块名
作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':
1 def fib(n): 2 a,b = 0,1 3 while b<n: 4 print(b,end = '') 5 a, b = b, a+b 6 print() 7 8 if __name__ == "__main__": 9 print(__name__) 10 num = input("num:") 11 fib(int(num))
py文件:直接运行这个文件,这个文件就是一个脚本
导入这个文件,这个文件就是一个模块
当一个py文件:
当做一个脚本的时候:能够独立的提供一个功能,能自主完成交互
当成一个模块的时候,能够被导入这调用这个功能,不能自主交互
一个文件中的__name__变量:
当这个文件被当做脚本执行的时候:__name__ == '__main__'
当这个文件被当做模块导入的时候:__name__ == '模块的名字'
6.模块搜索路径
在第一次导入某个模块时,会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用,如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找这个模块
所以模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
7.包
1.文件夹中有一个__init__.py文件
2.是几个模块的集合
3.无论是import形式还是from..import形式,凡是在导入语句中(而不是在使用时)遇到带点的,这是关于包才有的导入语法
4.包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
5.import导入文件时,产生名称空间中的名字来源于文件,import包产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
6.导入一个包相当于执行了这个包下面的__init__.py文件
关于包相关的导入语句也分为import和from..import..两种,但无论是哪种,在什么位置,都遵循一个原则:
凡是在导入时带点的,点的左边都必须是一个包
对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(他们都可以用点的方式调用自己的属性)
绝对导入:
在执行一个py脚本的时候,这个脚本以及这个脚本同级的模块中只能用绝对导入
缺点:
所有的导入都要从一个根目录下往后解释文件夹之间的关系
如果当前导入包的文件和被导入的包的位置关系发生了变化,那么所有的init文件都要做相应的调整
1 import glance 2 glance.__init__.py 3 import api 4 sys.path = [path] 5 glance.api.policy.get()
相对导入:
不需要去反复的修改路径
只要一个包中的所有文件夹和文件的相对位置不发生改变,init文件就不需要调整
不需要去关心当前这个包和被执行的文件之间的层级关系
缺点:
含有相对导入的py文件不能被直接执行
必须放在包中被导入的调用才能正常的使用
如果只是从包中导入模块的话,就不需要做任何多余的操作
如果希望导入包的时候,能够顺便的把模块也导入进来,需要设计init文件夹