模块
1 模块的定义
模块就是一系列功能的集合体
可以分为三大类:
I:内置的模块
II:第三方的模块
III:自定义的模块
2 模块的形式
模块有四种形式:
1 使用python编写的.py文件
2 已被编译为共享库或DLL的C或C++扩展
3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4 使用C编写并链接到python解释器的内置模块
现阶段使用到的为1和3
一个python文件本身就一个模块,文件名m.py,模块名叫m
3 模块的作用
-
内置与第三的模块
拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率
-
自定义的模块
可以将程序的各部分功能提取出来放到一模块中共享使用
减少代码冗余,程序组织结构更加清晰
4 模块的使用
4.1 import+模块名
4.1.1 初次导入模块
import foo
# 首次导入模块会发生3件事
# 1、执行foo.py
# 2、产生foo.py的名称空间,将foo.py运行过程中产生的名字都放入foo的名称空间中
# 3、在当前文件中产生的有一个名字foo,该名字指向2中产生的名称空间
4.1.2 重复导入模块
import foo
import foo
import foo
import foo
# 第一次之后的重复导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行foo.py文件内的代码
4.1.3 使用模块内名字
引用模块内名字时需要添加模块名+.+名字
print(foo.x)
print(foo.get)
print(foo.change)
注意:
模块名.名字,是指名道姓地找某一个模块名字对应的值,不会与当前名称空间中的名字发生冲突
x=1111111111111
print(x) # 本文件内定义的x
print(foo.x) # foo内定义的x
注意:
无论是查看还是修改操作的都是模块本身,与调用位置无关
import foo
x=333
foo.change() # 将x的值改成0
print(x) # 依旧为333
print(foo.x) # foo文件内的x已经改为0
4.1.4 可以以逗号为分隔符在一行导入多个模块
# 建议如下所示导入多个模块
import time
import foo
import m
# 不建议在一行同时导入多个模块
import time,foo,m
4.1.4 导入模块的规范
按照如下顺序导入:
I. python内置模块
II. 第三方模块
III. 程序员自定义模块
import time
import sys
import 第三方1
import 第三方2
import 自定义模块1
import 自定义模块2
import 自定义模块3
4.1.5 导入模块改名
import name1 as name2
import foo as f # f=foo
f.get() # 原来的foo.get()函数要使用f.get()才能调用
4.1.6 模块是第一类对象
模块同样可以赋值, 作参数 ...
import foo as f # f=foo
a = f
4.1.7 函数内导入模块
在函数内导入模块可以控制模块的作用域
使得调用函数时模块才生效
def func():
import foo
4.1.8 自定义模块的命名
自定义模块的命名应该采用纯小写+下划线的风格
import foo
4.2 from .... import .....
4.2.1 导入模块
# from ... import ...导入也发生了三件事
# 1、产一个模块的名称空间
# 2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
# 3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址
4.2.2 使用模块内名字
使用from .... import .....导入文件内名字就可以直接使用文件内变量
以from foo import x为例,本质是在当前文件全局中创建了x变量,其指向的是模块foo中值0的内存地址
当我们修改当前文件内全局变量x的指向地址,并不会对模块内的x产生影响,因为他们本就是两个不同的变量x
同样的,我们如果在导入模块中的x后对模块中的x进行更改,并不会对当前文件中的全局变量x产生影响
如果想将全局x更新成模块中的x值,重新导入即可,from foo import x
from foo import x # x=模块foo中值0的内存地址
from foo import get
from foo import change
print(x)
print(get)
print(change)
x=33333
print(x)
get()
change()
get()
print(x)
from foo import x # x=更改后的新地址
print(x)
4.2.3 可以以逗号为分隔符在一行导入多个模块
# 一行导入多个名字(不推荐)
from foo import x,get,change
# 分行导入多个名字(推荐)
from foo import x
from foo import get
from foo import change
# *:导入模块中的所有名字(特殊情况使用)
from foo import *
from socket import *
# __all__默认为含有模块中所有名字的列表
# *的导入方法本质是将__all__打散成多个名字,导入
from foo import *
print(x)
print(get)
print(change)
4.2.4 导入模块改名
from foo import get as g
print(g)
4.3 两种导入方式的优缺点
impot导入模块在使用时必须加前缀"模块."
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显得麻烦
from...impot...导入模块在使用时不用加前缀
优点:代码更精简
缺点:容易与当前名称空间混淆,导致数据覆盖的状况
5 python文件的两种用法
①当做程序运行
②当做模块被导入
5.1 两种形式的不同:
作为程序运行时该文件的名称空间会在这个程序全部执行完后回收
作为模块被导入时该名称空间会与源文件的某个名字绑定,导致在源文件程序执行完,回收所有名称空间之前不会对该名称空间进行回收,只有在源文件代码全部执行完----->绑定的名字被回收之后,该模块的名称空间才会回收
5.2 注意点:
作为模块被导入时该名称空间会与源文件的某个名字绑定,但是即使将该名字与模块的绑定关系解除
即del名字,使名字引用计数为0,也不会清理模块的名称空间,这是python的一种优化
5.3 __name__
两种形式输出的__name__不同
print(__name__)
# 1、当本文件被运行时,__name__的值为'__main__'
# 1、当本文件被当做模块导入时,__name__的值为'foo',即文件的名字
if __name__ == '__main__':
print('文件直接被执行')
get()
change()
else:
# 被当做模块导入时做的事情
print('文件被导入执行')
pass
6 模块的搜索路径优先级
无论是import还是from...import在导入模块时都涉及到查找问题
6.1 优先级
1、内存(内置模块)
2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块
import sys
print(sys.path)
# 值为一个列表,存放了一系列的文件夹
# 其中第一个文件夹是当前执行文件所在的文件夹
# 内存优先级的验证
import foo # 内存中已经有foo了
foo.say()
# 在10秒内将foo模块文件删除,查看还能否导入foo模块
import time
time.sleep(10)
import foo # 依旧能导入模块foo
foo.say()
6.2 添加路径
import sys
# 找foo.py就把foo.py的上一级文件夹添加到环境变量中
sys.path.append(r'/Users/PycharmProjects/s14/day21')
import foo
foo.say()
from foo import say
say()
6.3 查看加载模块
sys.modules可以查看已经加载到内存中的模块
import sys
import foo # foo=模块的内存地址
del foo
def func():
import foo # foo=模块的内存地址
func()
print('foo' in sys.modules)
print(sys.modules)