# 31. 模块的进阶
# from导入
from可以在模块中导入指定的模块属性(对象)、也就是说把指定的模块的对象导入到当前空间来
使用格式:
from 模块名 import 导入的对象名
# 模块文件
print("这是一个自定义模块中的打印输出")
name = "这是一个自定义模块中的变量"
def inso():
print("这是一个自定义模块中的函数")
# 导入单对象
from so_msg import inso
inso()
执行结果:
这是一个自定义模块中的打印输出
这是一个自定义模块中的函数
# 导入多对象
from so_msg import inso,name
inso()
print(name)
执行结果:
这是一个自定义模块中的打印输出
这是一个自定义模块中的函数
这是一个自定义模块中的变量
# 导入单对象时更名
from so_msg import inso as s
s()
执行结果:
这是一个自定义模块中的打印输出
这是一个自定义模块中的函数
# 导入多对象时更名
from so_msg import inso as s, name as nm
s()
print(nm)
执行结果:
这是一个自定义模块中的打印输出
这是一个自定义模块中的函数
这是一个自定义模块中的变量
# * 符号
*符号:代表导入模块中的所有对象
from so_msg import *
inso()
print(name)
执行结果:
这是一个自定义模块中的打印输出
这是一个自定义模块中的函数
这是一个自定义模块中的变量
# __add__的使用
add:用于模块文件,让模块文件限制 用 * 符号导入模块有多少变量,只是限制 * 符号
注意:add 必须要用 中括号 [ ] ,允许用 * 的对象要用字符串类型输入
模块文件
__all__ = ['inso']
print("这是一个自定义模块中的打印输出")
name = "这是一个自定义模块中的变量"
def inso():
print("这是一个自定义模块中的函数")
py执行文件
from so_msg import *
inso()
print(name)
执行结果:
这是一个自定义模块中的函数
NameError: name 'name' is not defined
# 把模块当成脚本执行
python执行有二种模式:脚本执行跟模块执行
模块执行
- import
- import
- from ... import
脚本执行
- 在pycharm中右键执行
- 在linux中,python 文件名 执行
- 等等
# name :判断是否在当前文件中执行
先来看看__name__的执行效果
在模块当前执行
name = "这是一个自定义模块中的变量1"
def inso():
print("这是一个自定义模块中的函数")
print(__name__)
执行结果:
__main__
在py文件中导入模块执行
from so_msg import *
执行结果:
so_msg
到这里有没有发现什么规律,__name__函数在模块的脚本执行返回的是"main",在另一个文件以模块导入的方式执行返回的是文件名"so_msg",所以可以用这个__name__来判断是否是当前文件执行
# 让模块文件有些代码只能在当地执行
使用__name__函数来进行判断,如果是当前文件就执行,如果不是当前文件就不执行
##模块文件
if __name__ == "__main__":print("你好")
name = "这是一个自定义模块中的变量1"
def inso():
print("这是一个自定义模块中的函数")
##py文件
from so_msg import *
inso()
print(name)
执行结果:
这是一个自定义模块中的函数
这是一个自定义模块中的变量1
这样子就可以让模块的一些执行输出,不会在导入模块的时候自动执行,也可以让模块文件能够脚本化,能当成模块文件,也能当成脚本文件
还可以这样理解:在编写py文件的时候,所有不在函数和类中封装的内容都应该写在,if name == 'main':这里
# 反射在模块中的补充
在反射中,是不是说过sys模块中的modules["main"],获取当前文件的内存地址
在这里在补充一点,sys模块中的modules["main"],无论是在模块中执行还是用于py文件执行都是显示当前执行空间的内存地址
## 模块文件执行
import sys
print(sys.modules["__main__"])
执行结果:
<module '__main__' from 'D:/python/PyCharm资源/one/模块/so_msg.py'>
## py文件执行
from so_msg import *
执行结果:
<module '__main__' from 'D:/python/PyCharm资源/one/模块/模块初始.py'>
有没有发现什么,为什么sys模块中的modules["main"],是在模块文件中的,在py文件中执行的结果竟然是py文件的内存地址。
这里强调一点,sys模块中的modules["main"],得到的结果来源于当前那个空间执行的py文件内存地址
那这样不是模块中不能使用反射了吗,因为反射的时候可以会用到sys模块中的modules["main"],来获取当前文件的内存地址,如果自己这样用,那么这个模块文件导入到另一个文件的时候,那反射还能正常用吗!!!
# 使用另一个方式
把sys模块中的modules["main"]中的__main__ 换成自己的__name__函数,因为modules出的值都会出于这文件关联的所有文件内存地址,__name__就是代表当前空间执行的文件的内存,其他文件都是以 {文件名:内存地址} 这种方式存储的,这样子使用__name__无论是在模块当前中执行也可以获取模块的内存地址,还是在Py文件导入模块的时候执行也可以获取模块的内存地址,这样子模块的反射就可以正常使用了
##模块文件
import sys
name = "这是一个自定义模块中的变量1"
def inso():
print("这是一个自定义模块中的函数")
getattr(sys.modules[__name__],"inso")()
print(getattr(sys.modules[__name__],"name"))
##py文件
from so_msg import *
执行结果:
这是一个自定义模块中的函数
这是一个自定义模块中的变量1
这样反射在模块文件中也可以正常使用,这样子也可以让模块文件当成脚本文件执行
# pyc编译文件
当python执行import 模块名 时,就会在当前目录下的__pycache__中生成一个编译好的文件
如果__pycache__不存在,会默认创建的
为什么要编译生成呢,python执行时,其实也是在编译文件,只是编译存放在内存
但是模块呢,在Python认为模块是一个常用又不常修改的py文件,那么他就有一个机制,执行的时候会把编译文件存放在指定的目录中,等下次执行调用模块的时候就可以直接调用这个文件,就不用重新编译模块文件了
这样到以后做比较大的项目的时候,会有效的提升代码的执行顺序
那么如果模块文件被修改了呢,放心,Python会自动的重新生成编译文件覆盖过去
注意:提高的代码效率是指代码中模块的导入效率,并不是代码的其它效率
# 重新加载模块
在py文件执行的时候,修改了已经导入的模块内容,是不生效的
## 模块文件
def inso():
print("这是一个自定义模块中的函数1")
## Py文件
import time
from so_msg import *
inso()
time.sleep(5)
inso()
执行结果:
这是一个自定义模块中的函数
这是一个自定义模块中的函数
## 当Py文件执行到time.sleep(5)的时候,就会停留5秒后在执行,这时候去修改模块文件的代码,可以看看等5秒后执行的是不是修改后的内容
那为什么不会生效呢,因为python执行时会把所有的包含模块的编译放在内存上,你修改的只是硬盘中的模块代码,又不是内存中编译好的内容,怎么可能会生效
# 使用importlib模块强制更新模块
这个超级超级不建议使用
## 模块文件
def inso():
print("这是一个自定义模块中的函数")
## py文件
import time
import importlib
import so_msg
so_msg.inso()
time.sleep(5)
importlib.reload(so_msg)
so_msg.inso()
执行结果:
这是一个自定义模块中的函数
这是一个自定义模块中的函数1
# 模块的循环导入
模块的循环导入,只有一个原则:不允许使用
python中模块是无法做到循环相互导入的。
# 模块文件:so_msg
import msg
def inso():
print("这是一个自定义模块中的函数1")
# Py执行文件:msg
import so_msg
so_msg.inso()
执行结果:
AttributeError: module 'so_msg' has no attribute 'inso'
为什么会提示找不到so_msg,因为so_msg文件执行是导入so_msg模块,从而执行so_msg模块文件,so_msg模块文件又从头开始执行,第一行代码就是导入msg模块,那么又会回来msg文件中从头开始执行,这时import msg,还会不会执行!!!
答案是不会,因为这模块文件已经编译导入内存中,Python会自动检测,如果发现导入过一次就不会在执行导入操作,那这样子,就到了执行代码环节
为什么会找不到,执行so_msg.inso(),那么在so_msg模块中的inso()函数会执行到没,没执行到那怎么找得到
所以在这建议永远不要写循环的模块架构