Python 的模块和包是代码组织与复用的核心机制:

  • 模块(Module):单个 .py 文件,封装变量、函数、类等,是代码复用的最小单元;模块是python程序的基本组织单位。
  • 包(Package):包含 __init__.py 文件的目录,用于组织多个相关模块,实现代码的分层管理。

一、模块(Module)

1. 如何使用模块?(核心操作:导入)

使用模块的核心是import语句,有 5 种常见导入方式,我会逐个讲清楚:

        语法import 模块名(导入整个模块)

        语法import 模块名 as 别名

        语法from 模块名 import 函数名/变量名/类名 (从模块中导入指定的部分

        语法from 模块名 import 名称 as 别名

        语法from 模块名 import * (不推荐)

2. 模块的「内置属性」

每个模块都有一些内置的特殊属性,帮你了解模块的信息

内置属性 核心含义 新手常用场景 / 示例
__name__

作用:获取模块的名字

  • 直接运行这个模块时:__name__ == "__main__"
  • 被别的文件导入时:__name__ == 模块名

模块自测(最核心用法

if __name__ == "__main__":

__file__ 返回模块文件的完整路径(绝对路径 / 相对路径,取决于系统) 查看模块位置
# 在main.py中执行
import calculator

# __name__:模块的名字
print(calculator.__name__)  # 输出:calculator

# __file__:模块的完整路径(告诉你模块文件存在哪里)
print(calculator.__file__)  # 输出:你的路径/calculator.py

# __doc__:模块的文档注释(如果模块开头写了"""注释""")
print(calculator.__doc__)  # 如果calculator.py开头有文档注释,会输出

3. 模块的「执行逻辑」(重点:if __name__ == "__main__"

现象:当你直接运行模块文件(比如python calculator.py),模块里的所有代码都会执行;但当你把模块导入到其他文件时,模块里的「可执行代码」也会被执行(这通常不是你想要的)。

解决方法:if __name__ == "__main__"

这个判断的作用:只有直接运行当前模块文件时,里面的代码才会执行;导入时不执行

# calculator.py
PI = 3.1415926

def add(a, b):
    return a + b

# 可执行代码(没有这个判断的话,导入时会打印)
print("我是calculator模块里的打印语句")

# 加上判断:只有直接运行calculator.py时,下面的代码才执行
if __name__ == "__main__":
    # 可以在这里写模块的测试代码
    print("直接运行calculator模块,执行测试")
    print("add(2,3)=", add(2, 3))

测试效果

  • 直接运行:python calculator.py输出:
    我是calculator模块里的打印语句
    直接运行calculator模块,执行测试
    add(2,3)= 5
    
  • 在 main.py 中导入 calculator 模块:输出:
    我是calculator模块里的打印语句  # 这行还是会执行(因为在判断外)
    
    ✅ 而if __name__ == "__main__"里的代码不会执行!

最佳实践:模块里的「测试代码」「示例代码」都放在if __name__ == "__main__"里。

4. 内置模块 vs 自定义模块 vs 第三方模块
类型 示例 获取方式
内置模块 jsonossys

Python 自带,无需安装直接导入即可

本质:Python 官方提前写好的、编译进解释器的 “功能文件”(大部分是 .py,核心模块是 C 实现)

自定义模块 json_utils.py

自己写的 .py 文件,按路径导入

本质:你自己写的 .py 文件

第三方模块 pandasrequests

需用 pip install 模块名 安装后导入

本质:开发者写好的 .py 文件,通过 pip 安装到你的 Python 环境里

二、包(Package):模块的「文件夹」

1. 包是什么?

包是:一个包含__init__.py文件的文件夹,这个文件夹里可以放:

  • 多个模块文件(.py
  • 子文件夹(子包,同样需要__init__.py

简单说:模块是「文件」,包是「装文件的文件夹」(必须有__init__.py)。

2. 包的结构示例

假设你要做一个「学生管理系统」,包的结构可以这样设计:

student_system/          # 根包(文件夹)
├── __init__.py          # 包的初始化文件(必须有)
├── basic_info.py        # 模块:处理学生基本信息(姓名、年龄)
├── score.py             # 模块:处理学生成绩(总分、平均分)
└── utils/               # 子包:工具类
    ├── __init__.py      # 子包的初始化文件(必须有)
    └── common.py        # 模块:通用功能(比如数据验证)

3. 如何创建包?

步骤 1:创建文件夹(包名)

比如创建student_system文件夹。

步骤 2:在文件夹里创建__init__.py文件

这个文件可以是空的(新手先这么做),也可以写包的初始化代码。

步骤 3:在文件夹里添加模块文件

比如basic_info.pyscore.py,以及子包utils(同样要__init__.py)。

4. 如何使用包中的模块?(导入方式)

还是用上面的student_system包举例,先写模块内容:

第一步:编写模块代码
# student_system/basic_info.py
def get_student_name(student_id):
    """根据学号获取姓名"""
    student_dict = {"001": "张三", "002": "李四"}
    return student_dict.get(student_id, "未知")

# student_system/score.py
def calculate_average(scores):
    """计算平均分"""
    if not scores:
        return 0
    return sum(scores) / len(scores)

# student_system/utils/common.py
def validate_student_id(student_id):
    """验证学号是否合法(必须是3位数字)"""
    return len(student_id) == 3 and student_id.isdigit()
第二步:导入包中的模块(4 种常见方式)

假设你在student_system文件夹外,创建一个main.py来调用:

方式 1:导入包中的模块(完整路径)
# main.py
# 导入student_system包中的basic_info模块
import student_system.basic_info as basic_info

# 调用模块中的函数
name = basic_info.get_student_name("001")
print("学生姓名:", name)  # 输出:学生姓名:张三
方式 2:从包中直接导入模块
# main.py
# 从student_system包中导入score模块
from student_system import score

# 调用函数
avg = score.calculate_average([85, 90, 95])
print("平均分:", avg)  # 输出:平均分:90.0
方式 3:从包的模块中导入指定函数
# main.py
# 从子包的模块中导入函数
from student_system.utils.common import validate_student_id

# 调用函数
print(validate_student_id("001"))  # 输出:True
print(validate_student_id("12"))   # 输出:False
方式 4:通过__init__.py简化导入(进阶)

如果觉得from student_system.utils.common import validate_student_id太长,可以修改__init__.py来简化:

  1. 修改student_system/utils/__init__.py
# student_system/utils/__init__.py
# 把common模块的validate_student_id导入到utils包的命名空间
from .common import validate_student_id
  1. 修改student_system/__init__.py
# student_system/__init__.py
# 把utils包的validate_student_id导入到根包的命名空间
from .utils import validate_student_id
# 同时导入basic_info的函数
from .basic_info import get_student_name
  1. 现在main.py可以这样导入(更简洁):
# main.py
from student_system import get_student_name, validate_student_id

print(get_student_name("002"))  # 输出:李四
print(validate_student_id("003"))  # 输出:True

5. __init__.py的核心作用

  • 标识文件夹是 Python 包:没有这个文件,Python 会把文件夹当成普通文件夹,无法导入其中的模块。
  • 初始化包的命名空间:可以在里面导入模块 / 函数,简化外部调用(上面的例子就是)。
  • 定义包的__all__属性(控制from 包 import *的导入内容):比如在student_system/__init__.py中写:
    # 当执行from student_system import *时,只导入这两个函数
    __all__ = ["get_student_name", "validate_student_id"]
    

三、模块的搜索路径(解决「导入失败」问题)

新手最常遇到的错误:ModuleNotFoundError: No module named 'xxx'—— 本质是 Python 找不到你的模块 / 包。

1. Python 查找模块的顺序

  1. 当前执行脚本的目录(你运行python main.py时,main.py 所在的目录)
  2. Python 的内置模块目录(比如/usr/lib/python3.10/,不用管)
  3. 第三方库安装目录(比如site-packages,pip 安装的库都在这里)
  4. sys.path 列表中的其他路径。

2. 查看 Python 的模块搜索路径

import sys

# 打印所有搜索路径(列表形式)
print(sys.path)

3. 解决「导入失败」的方法

方法 1:把模块 / 包放在当前执行目录

比如main.pyproject/目录,把student_system包也放在project/里,就能直接导入。

方法 2:临时添加搜索路径(适合临时测试)
# main.py
import sys
# 把包所在的目录添加到sys.path(替换成你的实际路径)
sys.path.append("/Users/xxx/Documents/my_project")

# 现在就能导入了
import student_system
方法 3:设置环境变量(永久生效)

在系统中设置PYTHONPATH环境变量,值为你的包 / 模块所在目录。

五、最佳实践

(1)命名规范:

        模块 / 包名用小写字母,多个单词用下划线(如 data_handler.py);
        避免与 Python 内置模块重名(如不要命名为 math.py)。

(2)避免循环导入:模块 A 导入模块 B,模块 B 又导入模块 A,会导致报错,需重构代码(如提取公共逻辑到新模块)。

(3)第三方包管理:

        用 pip install 包名 安装第三方包(如 pip install requests);
        用 requirements.txt 记录项目依赖:

requests==2.31.0
numpy==1.26.0

(4)模块测试:利用 if __name__ == "__main__" 编写模块自测代码,不影响导入使用。
 

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐