一、模块
模块就是一个包含了python定义和申明的文件,文件名就是模块的名字加上.py的后缀/
模块的分类:
1、使用python编写的py文件
2、已被编译位共享库或者DLL或C或者C++的扩展
3、包好一组模块的包
4、使用c编写并连接到python解释器的内置模块
使用模块是为了让我们写的代码可以重用,不至于把所有的文件都写到一个py文件内。如果都写在一个py文件内,项目大时,不易维护。
导入模块的两种方式
1、import模块
2、from XXX import XXXX
yitian.py
print('...................')
main_actor = '张无忌'
main_actress = '赵敏'
fan_main_actor = '成昆'
fan_main_actress = '周芷若'
def light_war():
print(f"{main_actor}破坏了{fan_main_actor}的阴谋诡计")
def shaolin_war():
print(f"{main_actor}打败了{fan_main_actress}")
def ending():
print(f"{main_actor}和{fan_main_actress}幸福的在一起了")
def change(name):
global main_actor
main_actor = name
print("..................."
金庸来了
jinyong.py
import sys
import yitian as yt # as 给模块重新命名# pycharm报错,模块路径有差异
# sys.path 搜索模块的路径
# print(sys.path)
# import yitian # 如果已经到如果该模块,此时则不会再执行模块中的代码了
print(yt.main_actor)
# print(main_actor) 报错 当前名称空间中没有main_actor
yt.light_war()
yt.shaolin_war()
yt.ending()
导入模块后的流程:
1、在导入模块的开始,python解释器会先通过sys.modules 来判断爱模块是否已经导入了该模块,如果导入了,则不会再导入。如果该模块还未导入过,则系统会做三件事:
1、为导入的模块创立新的名称空间
2、在新创建的名称空间中运行该模块中的代码
3、创建模块的名字,并使用该名称作为该模块在当前模块中引用的名字(前提时没有as)
可以使用globals来查看模块的名称空间
print(globals())
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000172F298C1D0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/python_workspace_hxt/day24 内置模块 re/yitian.py', '__cached__': None, 'main_actor': '张无忌', 'main_actress': '赵敏', 'fan_main_actor': '成昆', 'fan_main_actress': '周芷若', 'light_war': <function light_war at 0x00000172F2881E18>, 'shaolin_war': <function shaolin_war at 0x00000172F2BFA268>, 'ending': <function ending at 0x00000172F2BFA158>, 'change': <function change at 0x00000172F9C3A400>}
注: 由于模块在导入的时候会创建自己的名称空间,所以在使用模块中的变量的时候一般不会产生冲突
import yitian as yt
main_actor = '周游'
print(yt.main_actor) # 张无忌
print(main_actor) # 周游
特别注意:如果我们在不统的模块这种引入了同一个模块,并且在某一个模块中改变了被引入模块中的全局变量,则其他模块看到的之也跟着变,原因是python的模块只会引入一次,大家共享一个名称空间
在yitian.py中添加如下代码
def change():
global fan_main_actress
fan_main_actress = '呵呵'
jingyong1.py
import yitian as yt
yt.fan_main_actress = '哈哈'
jingyong.py
import yitian as yt
import jingyong1
print(yt.fan_main_actress) # 哈哈
出现上述问题的原因
1、大家同享一个模块的名称空间
2、在jinyong1.py中改变了反角的名字
解决方案:
利用__name__这个内置变量,在python中,每个模块都有自己的__name__但是这个__name__的值是不定的。当我们把一个模块作为程序运行的人口时,此时该模块的__name__是“__main__”而如果我们把模块导入时,此时模块内部的__name__就是该模块自身的名字
在jinyong1.py
print(__name__)
# 结果为__main__
在jinyong.py中
import jinyong1
print(__name__)
结果为 jinyong1
我们可以利用这个特性来控制模块内哪些代码是在被加载的时候就运行的,哪些时在模块被别人导入的时候就要执行的,也可以屏蔽掉一些不希望别人导入就运行的代码
if __name__=='__main__':
yitian.main_actor = '张无忌' # 此时,只有从该模块作为入口运行的时候才会把main_actor设置为张无忌
print('张无忌其实是一个渣男') # 只有运行该模块才会打印,import的时候是不会执行这里的代码的
我们还可以对导入的模块进行重命名
import yitian as yt # 导入yitian,但是名字被重命名为yt,就好比变量赋值一样
a = 1 b = a
yt.shaoli_war() # 此时可以正常运行
print(globals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002CC30D7C1D0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/python_workspace_hxt/day24 内置模块 re/practice24.py', '__cached__': None, 're': <module 're' from 'C:\\Users\\huxia\\AppData\\Local\\Programs\\Python\\Python36\\lib\\re.py'>, 'sys': <module 'sys' (built-in)>, 'yt': <module 'yitian' from 'F:\\python_workspace_hxt\\day24 内置模块 re\\yitian.py'>}
一次也可以导入多个模块
import time,random,json,yitian
正确的导入模块顺序:
1、所有的模块导入都要写在最上面,基本
2、先引入内置模块
3、再引入扩展模块
4、最后引入自己定义的模块
三、from XXX import XXX
在使用from的时候,python也会给我们的模块创建名称空间,这一点和import是一样的,但是from XXX import XXXX
的时候,只是把这个空间中的一些变量引入过来,部分导入。当一个模块中的内容过多的时候,可以选择性的导入要使用的内容。
from的坑:当我们从一个模块中引入一个变量的时候,如果当前文件中出现了崇明的变量时,会覆盖掉模块引入的哪个变量。
所以要切记,不可以重名,不仅仅变量名不要重复,我们自己创建的py文件的名字不要和系统内置的模块重名,否则,引入的模块都是python内置的模块。
那有⼀种 特殊的写法: from xxx import * 我们说此时是把模块中的所有内容都导入. 注意, 如果模块中 没有写出__all__ 则默认所有内容都导入. 如果写了了__all__ 此时导入的内容就是在__all__列表 中列出来的所有名字
# haha.py
__all__ = ["money", "eat"]
money = 100
def eat():
print("我是吃")
def drink():
print("我是呵呵")
# test.py
from haha import *
eat()
print(money)
drink() # 报错