一、什么是模块?
模块就是一系列功能的集合体,分为三大类:
I:内置的模块:例如input,print等
II:第三方的模块:例如time模块
III:自定义的模块:一个python文件本身就一个模块,文件名m.py,模块名叫m
模块有四种形式:
1 使用python编写的.py文件
2 已被编译为共享库或DLL的C或C++扩展
3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4 使用C编写并链接到python解释器的内置模块
二、为何要用模块
I:内置与第三的模块拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率
II:自定义的模块:
可以将程序的各部分功能提取出来放到一模块中为大家共享使用
好处是减少了代码冗余,程序组织结构更加清晰
三、如何用模块
1、首次导入模块会发生3件事
1、执行foo.py
2、产生foo.py的名称空间,将foo.py运行过程中产生的名字都丢到foo的名称空间中
3、在当前文件中产生的有一个名字foo,该名字指向2中产生的名称空间
y=333
z=444
import foo
-
之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码
import foo #只运行这一个!! import foo import foo import foo
2、引用:
print(foo.x)
print(foo.get)
print(foo.change)
强调1:模块名.名字,是指名道姓地问某一个模块要名字对应的值,不会与当前名称空间中的名字发生冲突
x=1111111111111
print(x) # 1111111111111
print(foo.x) # 1
强调2:无论是查看还是修改操作的都是模块本身,与调用位置无关
import foo
x=3333333333
# foo.get()
foo.change()
print(x)
print(foo.x)
foo.get()
3、可以以逗号为分隔符在一行导入多个模块
# 建议如下所示导入多个模块
import time
import foo
import m
# 不建议在一行同时导入多个模块
import time,foo,m
4、导入模块的规范
I. python内置模块
II. 第三方模块
III. 程序员自定义模块
import time
import sys
import 第三方1
import 第三方2
import 自定义模块1
import 自定义模块2
import 自定义模块3
5、import ... as ...
import foo as f # f=foo
f.get()
import Custommodule # 模块名太长的时候用 as name
# Custommodule.f1
# Custommodule.f2
# Custommodule.f3
import Custommodule as mmm
mmm.f1
mmm.f2
mmm.f3
6、模块是第一类对象
import foo
7、自定义模块的命名应该采用纯小写+下划线的风格
8、可以在函数内导入模块
def func():
import foo
9、Python文件的两种用途
1、运行文件;2、当做模块导入
9.1、执行Py文件和导入Py文件的区别是什么?
在运行文件时,如果有模块,首先会产生两个名称空间,因为内置名称空间和我们关系不大,所以不用讨论,然后产生两个全局名称空间,一个是运行文件的全局名称空间,一个是模块全局名称空间,而运行文件的全局名称空间中有模块名称空间的内存地址(import 模块名),所以在运行文件中可以通过(模块名.模块名称空间中的内容)对模块进行调用,而且这种调用方式与运行文件当中的名字没有关系,一切过程以定义阶段为准。
思考两个名称空间的回收:运行文件往往都是程序运行完毕之后进行回收,而模块却不是导完就进行回收,因为运行文件中的模块内容还被运行文件引用着,所以不能被回收,所以当运行文件结束,名称空间回收后,模块名称空间引用计数为0,即它就会被回收。
9.2、区分py文件的两种用途
print(__name__) # name = main
# 当foo.py被运行时__name__的值为__main__
# 当foo.py被当做模块导入时__name__的值为foo
if _name__ == '__main__':
print('文件执行')
get()
change()
else:
# 被当做模块导入时做的事情
print('文件被导入')
pass
if __name__ == '__name__': 这个文件当做程序运行时的代码
9.3、图例
10、from...import...导入模块
impot导入模块在使用时必须加前缀"模块."
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显得麻烦
from...import...发生的三件事情
1、产一个模块的名称空间
2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
3、在当前名称空间拿到一个名字,该名字指向模块名称空间中的某一个内存地址
from foo import x # x=模块foo中值0的内存地址
from foo import get
from foo import change
print(x)
print(get)
print(change)
x=333333333
print(x)
get()
change()
get()
print(x)
from foo import x # x=新地址
print(x)
from...impot...导入模块在使用时不用加前缀
优点:代码更精简
缺点:容易与当前名称空间混淆
from foo import x # x=模块foo中值1的内存地址
x=1111 # 但是这个x就是属于当前名称空间的,所以可以用一个值吧之前的那个值换掉
一行导入多个名字(不推荐)
from foo import x,get,change
11、from...import *(大多数不建议使用)
*:导入模块中的所有名字
name='egon'
from foo import *
print(name)
from socket import * # 当一个模块你要用到的东西很多
了解:
__all__ = ['x',] #控制*代表的名字有哪些,在模块当中,该行代码表示只拿x
from foo import *
print(x)
print(get)
print(change)
起别名
from foo import get as g
print(g)
12、循环导入问题(屎上雕花)
分析:
解决:
如需使用循环导入,只是在一个函数内用到另一个模块的名字,其他函数不用,就不要丢全局,直接丢函数当中。
13、模块的搜索优先级
无论是Import还是from...import,在导入模块时,都涉及到查找问题
import foo
from foo import x
优先级:
1、内存(内置模块)
2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块
import sys
值为一个列表,存放了一系列的对文件夹
其中第一个文件夹是当前执行文件所在的文件夹
print(sys.path)
"""
['F:\PythonLearn', 'F:\PythonLearn'(这个是pycharm给的), 'D:\pycharm\PyCharm 2019.3.3\plugins\python\helpers\pycharm_display', 'G:\python38\python38.zip'---》压缩包当成文件夹, 'G:\python38\DLLs', 'G:\python38\lib', 'G:\python38', 'G:\python38\lib\site-packages', 'D:\pycharm\PyCharm 2019.3.3\plugins\python\helpers\pycharm_matplotlib_backend']
"""
import foo # 内存中已经有foo了
foo.say()
import time
time.sleep(10)
import foo
foo.say()
了解:
# sys.modules查看已经加载到内存中的模块
import sys
import foo # foo=模块的内存地址
del foo
def func():
import foo # foo=模块的内存地址
func()
# print('foo' in sys.modules)
print(sys.modules)
import sys
# 找foo.py就把foo.py的文件夹添加到环境变量中
sys.path.append(r'/Users/linhaifeng/PycharmProjects/s14/day21/aa')
import foo
foo.say()
from foo import say