模块与包
文章目录
- 模块与包
- 一、模块
- 1.模块的导入方式
- 2.模块的循环导入问题
- 3.搜索路径与优先级
- 二、包
- 1.包的使用
- 2.绝对导入与相对导入
- 三、一般工程的开发目录规范
一、模块
模块是一系列功能的集合体,常见的模块形式(自定义模块、第三方模块、内置模块):
- 一个module.py文件就是一个模块,文件名是module.py,而模块名是module
- 一个包含有__init__.py文件的文件夹也是模块
- 已被编译为共享库或DLL的C或C++扩展
- 使用C编写并链接到python解释器的内置模块
为什么要使用模块?
- 用第三方或者内置的模块可以极大地提升开发效率
- 自定义模块即将我们自己程序中需要用到的公共的功能写入一个python文件,然后程序的各部分组件可以通过导入的方式来引用/重用自定义模块中的功能
1.模块的导入方式
import 模块名
from 模块名 import 具体的功能
对于导入的模块,也可以为它起一个别名:
import 模块名 as 自定义名字
from 模块名 import 具体的功能 as 自定义名字
#a.py
def add(x,y):
return x+y
#b.py
import a
print(a.add(1,2))
<<<3
from a import add
print(add(1,2))
<<<3
from a import add as d
print(d(1,2))
<<<3
导入模块时,解释器会干两件事情:
- 执行导入模块的代码(重复导入模块只有第一次导入时会执行模块代码)
- 产生一个名称空间存放产生的变量
由于是将产生的变量名存放在模块的名称空间中,所以使用时必须是模块名.变量的形式,例如上方代码中import a以后使用a中的add要写为a.add。
from 模块名 import 具体的功能时,解释器会将模块中的变量直接导入当前的名称空间中,若是当前名称空间中存在与导入功能重名的变量,后导入的变量会将之前的变量覆盖。
from 模块名 import * 表示导入某个模块中所有功能(该功能无法在函数内部调用)
模块的编写者可以在模块中定义__all__来控制*表达的意思。
#a.py
__all__=['get']
def add(x,y):
return x+y
get=9
#b.py
from a import *
#由于a的__all__中指定了'get',所以*只会导入get变量,而add不会被导入
print(get)
<<<9
print(add)
<<<NameError: name 'add' is not defined
2.模块的循环导入问题
#n.py
print('n')
from m import y
x=1
#m.py
print('m')
from n import x
y=2
<<<m
<<<n
<<<m
<<<ImportError: cannot import name 'x' from partially initialized module 'n'
执行m.py文件会先打印m,然后开始导入n模块,运行n模块的代码。在n模块的代码中打印n,并导入m模块,运行m模块的代码。再次运行m模块的代码时打印m,由于此前已经运行过n的代码了,所以此次之行m模块的代码不会在运行n模块的代码,而from n import x又要去导入x变量,目前的名称空间不存在x变量,最后报错。
为了避免上述导入时可能产生的问题,设计程序时应尽量避免循环/嵌套导入,如果多个模块需要共用某些数据,可以将数据存入单独的一个模块以供其他模块导入。
3.搜索路径与优先级
导入模块时查找模块的顺序是:
- 先从内存中已经导入的模块中寻找
- 内置的模块
- sys.path中找(sys.path的第一个值是当前执行文件的所在的文件夹)
当需要导入的模块不在sys.path列表中时,需要将路径添加到sys.path中。
二、包
包是模块的一种形式,包的本质就是一个含有__init__.py文件的文件夹。(python3中包即使没有__init__.py文件,直接导入包也不会报错)
1.包的使用
包内部的模块是用来被导入使用的,而不是被直接执行的。首次导入包时解释器会干两件事:
- 执行__init__.py文件
- 产生新的名称空间存放运行__init__.py时产生的变量
使用包时,可以直接包.功能名。例如上方的图片中import core后使用包中的buy函数有直接core.buy。
2.绝对导入与相对导入
python文件一般有两种用途:坐为执行文件、作为模块导入
如上图中所示,如果run.py表示执行文件,现在需要从setting.py中导入a变量,可以写为
import sys
sys.path.append('atm+购物车文件的绝对路径')
from conf.setting import a
这种导入方式称为绝对导入,也就是以顶级包(atm+购物车文件的绝对路径)为起始开始导入模块。
注意点:
- 绝对导入可以用于执行文件和模块文件
- 绝对导入时.左侧必须为文件/包
- 绝对导入以sys.path中的路径为基准(也就是说sys.path中必须包含atm+购物车文件的绝对路径)
如果现在需要在__init__.py中导入包定义的变量名(init.py文件一般用于存放包中定义的对象名称),如shopping中的buy函数,可以这样导入:
from .shopping import buy
这种调用方式称为相对导入
注意点:
- 相对导入只能用于模块文件中
- 相对导入左侧的.必须写,表示当前模块所在的目录(core)。若在相对导入中需要导入上一级目录的模块,可以使用两个.表示
三、一般工程的开发目录规范
在主目录下存放执行文件start.py、readme.md(工程的相关说明)、requirements.txt(工程依赖的python第三方模块)
在conf文件夹中存放配置文件setting.py
在lib文件夹中存放常用的模块commen.py
在core文件夹中存放核心的代码
在api文件夹下存放接口文件
在db文件夹下存放数据相关的代码
在log文件夹中存放日志相关的代码