zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Python基础-6 模块和包

2023-06-13 09:15:39 时间

6.模块和包

模块modules

在之前的程序里,你可能用过类似from math import pi的语句来导入变量或函数。这其实就是在使用模块

模块:Python将程序存入一个文件,可在解释器中运行。这个文件就是模块

模块中的语句可以导入(import)到其他Python程序中。

使用模块的好处:模块化,每个模块实现相关的功能;避免文件过长和混乱。

创建模块

新建一个文件(文件名为模块名.py),在文件里写程序。

举个例子:创建一个和三角形相关的模块:

新建文件tri_f.py,然后在里面写入:

import math

print("tri_f 模块 开始")


def edge_length(a, b, c):
    """返回三边长度之和"""
    return a + b + c


def area(a, b, c):
    """返回三角形面积"""
    p = (a + b + c) / 2
    s = math.sqrt(p * (p - a) * (p - b) * (p - c))
    return s


print("tri_f 模块 结束")

然后保存(Ctrl+s)。这样模块就创建好了。

使用模块

使用模块通过import语句导入模块中的变量定义、函数等可执行语句等。

例,使用模块tri.f

tri_f.py同级目录下创建test.py

注意:如果不是同级目录,解释器会找不到,需要在sys.path中添加查找路径,如

import sys sys.path.append(r'D:\PY_TEST\pythonProject\6modules') #替换为自己的目录

a, b, c = 3, 4, 5
# 从模块导入特定函数
from tri_f import area   # 从tri_f模块导入函数area的定义
print(area(a, b, c))   # 然后就可以使用函数area,计算三角形面积了

# 导入模块 
import tri_f                 #导入 tri_f模块
print(tri_f.area(a, b, c))  # 函数前面需要加上模块名

# 给模块起别名
import tri_f as tr
print(tr.area(a, b, c))

# (不推荐)从模块导入全部函数(_开头的函数除外)
from tri_f import *
print(area(a, b, c))
print(edge_length(a, b, c))

运行test.py我们得到下面结果:

tri_f 模块 开始
tri_f 模块 结束
6.0
6.0
6.0
6.0
12.0

通过import模块 ,我们不仅导入了函数,还会执行模块中的语句。

总结一下,Import的用法:

# 从模块导入特定函数
from 模块 import 函数

# 导入模块 
import 模块

# 给模块起别名
import 模块 as 别名


# (不推荐)从模块导入全部函数(_开头的函数除外)及变量
from 模块 import *

模块名__name__

你可能看到过 下面的语句:

 if __name__ == '__main__':
    print('hello')

这里的__name__实际上就是模块的名字。模块被导入时,__name__是模块的文件名。当这个模块作为主程序运行时,模块的__name__会赋值为'__main__'

import math
print('name=',__name__)

def edge_length(a, b, c):
    """返回三边长度之和"""
    return a + b + c


def area(a, b, c):
    """返回三角形面积"""
    p = (a + b + c) / 2
    s = math.sqrt(p * (p - a) * (p - b) * (p - c))
    return s


if __name__ == '__main__':
    print(area(3, 4, 5))
    print('hello')

运行tri_f.py,输出:

name= __main__
6.0
hello

运行test.py时,tri_f中的__name__就会变成模块名 tri_f,所以不会执行tri.f模块中if里的内容:

if __name__ == '__main__':
    print(area(3, 4, 5))
    print('hello')

模块详情

import语句导入模块时发生的事情:

执行模块中语句(包括定义函数等)。

注意:

!模块中的语句用于初始化模块,且仅在 import 语句 第一次 遇到模块名时执行(防止重复)。

!需要注意,如果有多个相同函数名,最后定义的函数会把之前的同名函数覆盖掉。

!可以用与访问模块函数一样的标记法,访问模块的全局变量modname.itemname

模块有自己的私有符号表,用作模块中所有函数全局符号表。因此,模块内全局变量不会与用户定义的全局变量发生冲突。(别纠结,命名空间在第九章类会详细说)

包package

创建包

包是装着模块的文件夹,文件夹下必须含 __init__.py 文件。

最简情况下,__init__.py 只是一个空文件,但该文件也可以执行包的初始化代码,或设置 __all__ 变量,详见下文(从包中导入*)。

sound/                          #顶层包
      __init__.py               #初始化
      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/                  #子包,用于过滤
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

使用包

从包导入与从模块导入非常类似。

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

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)

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

from sound.effects.echo import echofilter

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

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

注意,使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的函数、类或变量等其他名称。

优先查找包中定义的函数、类或变量等,未找到则假定 item 是模块,并尝试加载模块。如果仍然找不到 item,则触发 ImportError 异常。

相反,使用 import item.subitem.subsubitem 句法时,除最后一项外,每个 item 都必须是包;最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量。

从包中导入 *

类似模块导入*,使用 from sound.effects import * 时,该语句应该导入包的所有子模块。但是这可能会导入太多东西, 浪费时间且造成冲突。因此,使用 from sound.effects import *只会导入在__init__.py__all__变量里的模块。

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

相对导入

包中含有多个子包时还可以用 import 语句的 from module import name 形式执行相对导入。这些导入语句使用前导句点表示相对导入中的当前包和父包。例如,相对于 effect包下的surround 模块,可以使用:

from . import echo
from .. import formats
from ..filters import equalizer