跳至主要內容

模块

Sankgao约 3196 字大约 11 分钟LanguagesPython

在 Python 中,一个扩展名为 .py 的文件就称为一个 模块。

通常情况下,把能够实现某一特定功能的代码放置在一个文件中作为一个模块,从而方便其它程序和脚本导入使用。另外使用模块也可以避免函数名和变量名冲突。

模块可以提高代码的可维护性和可用性。

自定义模块

自定义模块有两个作用:

  • 规范代码,让代码更易于阅读
  • 方便其它程序使用已经编写好的代码,提高开发效率

自定义模块主要分为两部分:创建模块导入模块。

创建模块

创建模块时,可以将模块中相关的代码(变量定义和函数定义等)编写在一个单独的文件中,并且将该文件命名为 模块名+.py 的形式。

创建一个用于根据身高、体重计算 BMI 指数的模块,命名为 bmi.py,其中 bmi 为模块名,.py 为扩展名。例如:

def fun_bmi(person, height, weight):
    """
    功能:根据身高和体重计算 BMI 指数
    :param person: 姓名
    :param height: 身高,单位:米
    :param weight: 体重,单位:千克
    """
    
    print(person + " 的身高:" + str(height) + " 米 \t体重:" + str(weight) + " 千克")
    
    bmi = weight / (height * height)
    print(person + " 的 BMI 指数为:" + str(bmi))


def fun_bmi_upgrade(*person):
    """
    功能:根据身高和体重计算 BMI 指数(升级版)
    :*param *person: 可变参数,该参数中需要传递带 3 个元素 列表,分别为:姓名、身高(单位:米)和体重(单位:千克)
    :return: 
    """
    # 此处省略了函数主体代码

使用 import 语句导入模块

使用模块需要先以模块的形式加载模块中的代码。

语法格式import modulename [as alias]

  • modulename:要导入的模块名
  • as alias:如果模块名太长,可以给模块起一个别名,通过别名也可以使用模块

例如:

# 导入模块
import bmi

bmi.fun_bmi("张三", 1.75, 120)  # 执行模块中的 fun_bmi 函数

提示

使用 import 语句导入模块时,模块名是区分字母大小写的

使用 from...import 语句导入模块

在使用 import 语句导入模块时,每执行一条 import 语句都会创建一个新的命名空间(namespace),并且在该命名空间中执行与 .py 文件相关的所有语。在执行时,需在具体的变量、函数和类名前加上 模块名. 前缀。如果不想在每次导入模块时都创建一个新的命名空间,而是将具体的定义导入到当前命名空间中,可以使用 from...import 语句,使用 from...import 语句 导入模块后,不需要再添加前缀,直接通过具体的变量、函数和类名等访问即可。

语法格式from modulename import member

  • modulename:模块名,区分字母大小写
  • member:指定要导入的变量、函数或者类等,可以同时导入多个定义,各个定义之间用逗号 , 分隔,也可以使用 *

提示

在使用 from...import 语句 导入模块中的定义时,需要保证所导入的内容在当前的命名空间中是唯一的,否则将出现冲突,后导入的同名变量、函数或者类会覆盖先导入的

例如:导入两个包括同名的函数模块。

"""
创建矩形模块,对应的文件名为 rectangle.py
"""

def girth(width, height):
    """
    功能:计算矩形周长
    :param widgh: 宽度
    :param height: 高
    :return:
    """

    return (width + height) * 2


def area(width, height):
    """
    功能:计算矩形面积
    :param width: 宽度
    :param height: 高
    :return:
    """

    return width * height


if __name__ == '__main__':
    print(area(10, 20))

"""
创建圆形模块,对应的文件名 circular.py
"""

import math

PI = math.pi


def girth(r):
    """
    功能:计算圆形周长
    :param r: 半径
    :return:
    """

    return round(2 * PI * r, 2)


def area(r):
    """
    功能:计算圆形面积
    :param r: 半径
    :return:
    """

    return round(PI * r * r, 2)


if __name__ == '__main__':
    print(girth(10))

"""
创建 computc.py 文件,导入矩形模块和圆形模块
"""

# 使用 from...import 导入
from rectangle import *
from circular import *

if __name__ == '__main__':
    print("矩形的周长为;", girth(10, 20))
    print("圆形的周长为:", girth(10))


# 输出结果
TypeError: girth() takes 1 positional argument but 2 were given。参数为 1 个,但指定了 2 个参数
圆形的周长为: 62.83


# 使用 import 语句导入
import rectangle as r
import circular as c

if __name__ == '__main__':
    print("矩形的周长为:", r.girth(10, 20))
    print("圆形的周长为:", c.girth(10))


# 输出结果
矩形的周长为: 60
圆形的周长为: 62.83

模块搜索目录

当使用 import 语句导入模块时,默认情况下,会按照以下顺序进行查找:

  1. 在当前目录(即执行的 Python 脚本文件所在的目录)下查找
  2. 到 PYTHONATH(环境变量)下的每个目录中查找
  3. 到 Python 的默认安装目录下查找

以上各个目录的具体位置保存在标准模块 syssys.path 变量中。可以通过以下代码输出具体的目录:

import sys

print(sys.path)


# 输出结果
['E:\\SourceCode\\Python\\PythonProject', 'E:\\SourceCode\\Python\\PythonProject', 'E:\\Software\\PyCharm\\PyCharm 2022.1.2\\plugins\\python\\helpers\\pycharm_display', 'E:\\Software\\Python3\\python310.zip', 'E:\\Software\\Python3\\DLLs', 'E:\\Software\\Python3\\lib', 'E:\\Software\\Python3', 'E:\\Software\\PyCharm\\pythonProject\\venv', 'E:\\Software\\PyCharm\\pythonProject\\venv\\lib\\site-packages', 'E:\\Software\\PyCharm\\PyCharm 2022.1.2\\plugins\\python\\helpers\\pycharm_matplotlib_backend']

以下三种方法,添加指定模块目录到 sys.path

  • 临时添加

    只在当前执行文件的窗口有效,窗口关闭后失效。例如:

    import sys
    
    sys.path.append("E:\\SourcdCode\\Python\\demo")
    
  • 增加 .pth 文件(推荐)

    通过该方法添加的目录只在当前版本的 Python 中有效,并且创建完成后,要重新打开要执行的 Python 文件。

    例如:在 Python 安装目录下的 Lib\site-packages 子目录中,创建扩展名为 .pth 文件,在该文件中添加要导入模块所在的目录。

    E:\\SourcdCode\\Python\\demo
    
  • 在 PYTHONPATH 环境变量中添加

    通过该方法添加的目录可以再不同版本的 Python 中共享,并且创建完成后,要重新打开要执行的 Python 文件。

    例如:打开 环境变量 框,如果没有 PYTHONPATH 系统变量,则需要先创建一个,否则直接选中 PYTHONPATH 系统变量,再点击 编辑 按钮,并且再弹出的对话框 变量值 文本中添加新的模块目录

以主程序的形式执行

"""
创建名为 christmastree 模块
"""

pinetree = "我是一颗松树"


def fun_christmastree():
    """
    功能:一个梦
    :return:
    """

    pinetree = "挂上彩灯、礼物...我变成一颗圣诞树\n"
    print(pinetree)


print("\n下雪了...\n")
print(('-' * 20), "开始做梦", ('-' * 20))
fun_christmastree()
print(('-' * 20), "梦醒了...", ('-' * 20))
pinetree = "我身上落满雪花," + pinetree
print(pinetree)

"""
创建名为 main.py 的文件,导入 christmastree 模块并执行
"""

import christmastree

print(christmastree.pinetree)


# 输出结果
下雪了...
-------------------- 开始做梦 --------------------
挂上彩灯、礼物...我变成一颗圣诞树
-------------------- 梦醒了... --------------------
我身上落满雪花,我是一颗松树
我身上落满雪花,我是一颗松树

导入模块后,不仅输出了全局变量的值,而且模块中原有的测试代码也被执行了,这个结果不是想要的。在模块中将原本直接执行的测试代码放在一个 if 语句中,修改后的代码:

"""
创建名为 christmastree 模块
"""

pinetree = "我是一颗松树"


def fun_christmastree():
    """
    功能:一个梦
    :return:
    """

    pinetree = "挂上彩灯、礼物...我变成一颗圣诞树\n"
    print(pinetree)


# 使用此方法时,下面的语句在导入到其他文件中时不执行
if __name__ == '__main__'
    print("\n下雪了...\n")
    print(('-' * 20), "开始做梦", ('-' * 20))
    fun_christmastree()
    print(('-' * 20), "梦醒了...", ('-' * 20))
    pinetree = "我身上落满雪花," + pinetree
    print(pinetree)

"""
创建名为 main.py 的文件,导入 christmastree 模块并执行
"""

import christmastree

print(christmastree.pinetree)  # 输出结果:我是一颗松树

提示

在每个模块的定义中都包括一个记录模块名称的变量 __name__,程序可以检查该变量,以确定它们在哪个模块中执行。如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的 __name__ 变量的值为 __main__

Python 中的包

包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下。这样即可以起到规范代码的作用,又能避免模块名重名引起的冲突。简单理解就是 文件夹,只不过在该文件夹下必须存在一个名称为 __init__.py 的文件。

包结构

先创建名为 shop 项目,然后在该包下又创建了 adminhometemplates 包和一个 manage.py 的文件,最后在每个包中,又创建了相应的模块。

shop  # 项目名
├── admin  # 用于保存后台文件的包
│   ├── forms.py
│   ├── __init__.py
│   └── views.py
├── home  # 用于保存前台文件的包
│   ├── forms.py
│   ├── __init__.py
│   └── views.py
├── templates  # 用于保存模板文件的包
│   ├── __init__.py
│   └── models.py
└── manage.py  # 入口程序

创建和使用包

创建包,实际上就是创建一个文件夹,并且在该文件夹中创建一个名称为 __init__.py 的文件。__init__.py 文件是一个模块文件,模块名为对应的包名。例如:在 settings 包中创建的 __init__.py 文件,对应的模块名为 settings。在 __init__.py 文件中可以不写任何代码,也可以编写一些 Python 代码,在 __init__.py 文件中所编写的代码,在导入包时会自动执行。

  1. 创建名为 settings 的文件夹

  2. settings 文件夹中创建 __init__.py 文件

  3. settings 包中创建名为 size 的模块,在模块中定义两个变量。例如:

    width = 800
    height = 600
    

在创建包之后就可以在包中创建相应的模块,然后再使用 import 语句从包中加载模块,加载模块通常有以下三种方式:

  • 通过 import + 完整包名 + 模块名 形式加载指定模块

    通过该方法导入模块,在使用时需要在变量名前加入 settings.size 前缀。例如:

    import settings.size
    
    if __name__ == '__main__':
        print("宽度:", settings.size.width)  # 输出结果:宽度: 800
        print("高度:", settings.size.height)  # 输出结果:高度: 600
    
  • 通过 from + 完整包名 + import + 模块名 形式加载指定模块

    通过该方法导入模块,在使用时不需要带包前缀,但是需要带模块名。例如:

    from settings import size
    
    if __name__ == '__main__':
        print("宽度:", size.width)  # 输出结果:宽度: 800
        print("高度:", size.height)  # 输出结果:高度: 600
    
  • 通过 from + 完整包名 + 模块名 + import + 定义名 形式加载指定模块

    通过该方法导入模块的函数、变量或类后,在使用时直接使用函数、变量或类名即可。例如:

    from settings.size import width, height
    
    if __name__ == '__main__':
        print("宽度:", width)  # 输出结果:宽度: 800
        print("高度:", height)  # 输出结果:高度: 600
    

    提示

    通过 from + 完整包名 + 模块名 + import + 定义名 形式加载指定模块时,可以使用 * 号代替定义名,表示加载该模块下的全部定义

定义 size 模块,在该模块中定义两个保护类型的全局变量,定义 change() 函数,用于修改两个全局变量的值,再定义两个函数,分别用于获取两个保护类型的全局变量。例如:

_width = 800
_height = 600


def change(w, h):
    global _width
    _width = w
    global _height
    _height = h


def getwidth():
    global _width
    return _width


def getheight():
    global _height
    return _height

settings 包的上层目录创建名为 main.py 的文件,在该文件中导入 settings 包下的 size 模块的全部定义。例如:

from settings.size import *

if __name__ == '__main__':
    change(1024, 768)
    print("宽度:", getwidth())  # 输出结果:宽度: 800
    print("高度:", getheight())  # 输出结果:高度: 600

引入其它模块

在 Python 中,除了可以自定义模块外,还可以引用其它模块,主要包括使用标准模块和第三方模块。

导入标准模块

直接使用 import 语句导入 Python 文件中即可,导入后通过模块名调用其提供的函数。例如:

import random

print(random.randint(0, 10))  # 输出结果:7

使用第三方模块

可以在 Python 官方推出的 http://pypi.python.org/pypiopen in new window 中找到第三方模块。使用第三方模块,需要先下载并安装该模块,然后就可以像使用标准模块一样导入并使用了。

下载和安装第三方模块可以使用 Python 提供的 pip 命令实现。

语法格式pip <command> [modulename]

  • command:指定要执行的命令。常用的参数值有 install(用于安装第三方模块)、uninstall(用于卸载已经安装的第三方模块)、list(用于显示已经安装的第三方模块)等
  • modulename:可选参数,用于指定要安装或者卸载的模块名,当 commandinstalluninstall 时不能忽略

例如:

pip install numpy  # 安装 numpy 模块