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__ 变量,详见下文。

还可以从包中导入单个模块,例如:

import sound.effects.echo

这段代码加载子模块 sound.effects.echo ,但引用时必须使用子模块的全名:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

另一种导入子模块的方法是 :

from sound.effects import echo

这段代码还可以加载子模块 echo ,并且不加包前缀也可以使用。因此,可以按如下方式使用:

echo.echofilter(input, output, delay=0.7, atten=4)

另一种变体是直接导入所需的函数或变量:

from sound.effects.echo import echofilter

同样,这样也会加载子模块 echo,但可以直接使用函数 echofilter()

echofilter(input, output, delay=0.7, atten=4)

 

从包中导入 *

使用 from sound.effects import * 时会发生什么?理想情况下,该语句在文件系统查找并导入包的所有子模块。这项操作花费的时间较长,并且导入子模块可能会产生不必要的副作用,这种副作用只有在显式导入子模块时才会发生。

唯一的解决方案是提供包的显式索引。import 语句使用如下惯例:如果包的 __init__.py 代码定义了列表 __all__,运行 from package import * 时,它就是用于导入的模块名列表。发布包的新版本时,包的作者应更新此列表。如果包的作者认为没有必要在包中执行导入 * 操作,也可以不提供此列表。例如,sound/effects/__init__.py 文件包含以下代码:

__all__ = ["echo", "surround", "reverse"]

即,from sound.effects import * 将导入 sound 包中的这三个命名子模块。

如果没有定义 __all__from sound.effects import * 语句 不会 把包 sound.effects 中所有子模块都导入到当前命名空间;该语句只确保导入包 sound.effects (可能还会运行 __init__.py 中的初始化代码),然后,再导入包中定义的名称。这些名称包括 __init__.py 中定义的任何名称(以及显式加载的子模块),还包括之前 import 语句显式加载的包里的子模块。请看以下代码:

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

本例中,执行 from...import 语句时,将把 echo 和 surround 模块导入至当前命名空间,因为,它们是在 sound.effects 包里定义的。(该导入操作在定义了 __all__ 时也有效。)

虽然,可以把模块设计为用 import * 时只导出遵循指定模式的名称,但仍不提倡在生产代码中使用这种做法。

记住,使用 from package import specific_submodule 没有任何问题! 实际上,除了导入模块使用不同包的同名子模块之外,这种方式是推荐用法。