模块

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 模块的作用

  1. 内置与第三的模块

    ​ 拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率

  2. 自定义的模块
    可以将程序的各部分功能提取出来放到一模块中共享使用
    减少代码冗余,程序组织结构更加清晰

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)
 posted on 2020-03-26 22:02  wwwpy  阅读(171)  评论(0编辑  收藏  举报