Python 模块
一. 模块的基本定义
编写程序时,我们会反复的使用我们自定义的函数或者功能块来组装。将这些自定义的函数等保存在指定的文件内,需要的时候就使用,这样就极大的提高了代码的复用和效率。这个文件就是一个模块,那如何使用这个文件呢?
import关键字 + 模块名
import sys
print(sys.path)
# 输出搜索路径 ['D:\www\21yi.com', 'D:\www\21yi.com', 'C:\Program Files (x86)\python3\python38.zip', 'C:\Program Files (x86)\python3\DLLs', 'C:\Program Files (x86)\python3\lib', 'C:\Program Files (x86)\python3', 'D:\courses\21yi.com', 'D:\courses\21yi.com\lib\site-packages']
二. 模块的创建与使用
1. 创建一个模块
新建一个tools.py,创建一个工具集模块
import os
def create_dir(path):
if not os.path.exists(path):
os.makedirs(path)
try:
os.chown(path, 33, 33)
except Exception as e:
print(e)
return True
def put_content(file, content):
f = open(file, "wr")
f.write(content)
f.close()
2. import导入模块
import module1[, module2[,... moduleN]
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
一个模块只会被导入一次,不管你执行了多少次import。
解释器会在搜索路径内搜索模块文件,如果找到了,就引入。搜索路径就是基本概念里的示例代码sys.path打印出来的路径。
import tools
tools.create_dir("21yi.com") #使用tools工具集的create_dir来创建一个目录
# dir函数,可以打印出模块有哪些方法和属性
dir(tools) # ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'create_dir', 'os', 'put_content']
3. from import导入部分模块
有时候,我们可能只是需要模块的极少功能,那我们可以使用from impor导入部分
from tools import create_dir
create_dir("21yi.com")
或者全部功能都导入
from tools import *
create_dir("21yi.com")
三.包
包是一种用“点式模块名”构造 Python 模块命名空间的方法。例如,模块名 A.B
表示包 A
中名为 B
的子模块。正如模块可以区分不同模块之间的全局变量名称一样,点式模块名可以区分 NumPy 或 Pillow 等不同多模块包之间的模块名称。
假设要为统一处理声音文件与声音数据设计一个模块集(“包”)。声音文件的格式很多(通常以扩展名来识别,例如:.wav
, .aiff
, .au
),因此,为了不同文件格式之间的转换,需要创建和维护一个不断增长的模块集合。为了实现对声音数据的不同处理(例如,混声、添加回声、均衡器功能、创造人工立体声效果),还要编写无穷无尽的模块流。下图以分级文件系统形式展示这个包的架构:
sound/ 顶层包 __init__.py 初始化 sound 包 formats/ 文件格式转换子包 __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ 声音效果子包 __init__.py echo.py surround.py reverse.py ... filters/ filters 子包 __init__.py equalizer.py vocoder.py karaoke.py ...
导入包时,Python 搜索 sys.path
里的目录,查找包的子目录。
Python 只把含 __init__.py
文件的目录当成包。这样可以防止以 string
等通用名称命名的目录,无意中屏蔽出现在后方模块搜索路径中的有效模块。 最简情况下,__init__.py
只是一个空文件,但该文件也可以执行包的初始化代码,或设置 __all__
变量,详见下文。
还可以从包中导入单个模块,例如:
这段代码加载子模块 sound.effects.echo
,但引用时必须使用子模块的全名:
另一种导入子模块的方法是 :
这段代码还可以加载子模块 echo
,并且不加包前缀也可以使用。因此,可以按如下方式使用:
另一种变体是直接导入所需的函数或变量:
同样,这样也会加载子模块 echo
,但可以直接使用函数 echofilter()
:
从包中导入 *
使用 from sound.effects import *
时会发生什么?理想情况下,该语句在文件系统查找并导入包的所有子模块。这项操作花费的时间较长,并且导入子模块可能会产生不必要的副作用,这种副作用只有在显式导入子模块时才会发生。
唯一的解决方案是提供包的显式索引。import
语句使用如下惯例:如果包的 __init__.py
代码定义了列表 __all__
,运行 from package import *
时,它就是用于导入的模块名列表。发布包的新版本时,包的作者应更新此列表。如果包的作者认为没有必要在包中执行导入 * 操作,也可以不提供此列表。例如,sound/effects/__init__.py
文件包含以下代码:
即,from sound.effects import *
将导入 sound
包中的这三个命名子模块。
如果没有定义 __all__
,from sound.effects import *
语句 不会 把包 sound.effects
中所有子模块都导入到当前命名空间;该语句只确保导入包 sound.effects
(可能还会运行 __init__.py
中的初始化代码),然后,再导入包中定义的名称。这些名称包括 __init__.py
中定义的任何名称(以及显式加载的子模块),还包括之前 import
语句显式加载的包里的子模块。请看以下代码:
本例中,执行 from...import
语句时,将把 echo
和 surround
模块导入至当前命名空间,因为,它们是在 sound.effects
包里定义的。(该导入操作在定义了 __all__
时也有效。)
虽然,可以把模块设计为用 import *
时只导出遵循指定模式的名称,但仍不提倡在生产代码中使用这种做法。
记住,使用 from package import specific_submodule
没有任何问题! 实际上,除了导入模块使用不同包的同名子模块之外,这种方式是推荐用法。