Python实战第13期:模块与包

引言:为什么需要模块和包?

在前面的课程中,我们把所有代码都写在一个文件里。但当程序越来越复杂时,一个文件会变得非常长,难以维护。

这时候就需要用到模块 和包:

  • 模块:一个.py文件就是一个模块
  • 包:包含多个模块的目录

通过模块和包,我们可以:

  • 把代码组织成多个文件
  • 复用已有的代码
  • 使用别人写好的库

模块和包是Python代码组织的基础,掌握了它们,你就能编写更大、更复杂的程序了。


一、导入模块

1. 什么是模块

模块是一个包含Python代码的.py文件。模块可以定义函数、类和变量,也可以包含可执行的代码。

python 复制代码
# math_module.py
import math

def circle_area(radius):
    """计算圆的面积"""
    return math.pi * radius ** 2

def circle_perimeter(radius):
    """计算圆的周长"""
    return 2 * math.pi * radius

PI = math.pi

2. import语句

使用 import 语句导入整个模块。

python 复制代码
# 导入整个模块
import math

# 使用模块中的函数
print(math.sqrt(16))  # 输出:4.0
print(math.pi)        # 输出:3.141592653589793

# 导入多个模块
import os
import sys

print(os.getcwd())
print(sys.version)

3. from...import语句

使用 from...import 语句导入模块中的特定内容。

python 复制代码
# 导入特定的函数
from math import sqrt, pi

print(sqrt(16))  # 输出:4.0
print(pi)        # 输出:3.141592653589793

# 导入所有内容(不推荐)
from math import *

print(sqrt(16))  # 可以直接使用,不需要math.前缀

💡 提示:

  • import module:需要使用 module.function() 调用
  • from module import function:可以直接使用 function() 调用
  • from module import *:导入所有内容,但可能导致命名冲突

4. as别名

使用 as 关键字给模块或函数起别名。

python 复制代码
# 给模块起别名
import numpy as np

arr = np.array([1, 2, 3])
print(arr)

# 给函数起别名
from math import sqrt as square_root

print(square_root(16))  # 输出:4.0

# 常用别名
import pandas as pd
import matplotlib.pyplot as plt

5. 导入自定义模块

python 复制代码
# mymodule.py
def greet(name):
    return f"Hello, {name}!"

PI = 3.14159

# main.py
import mymodule

print(mymodule.greet("小明"))  # 输出:Hello, 小明!
print(mymodule.PI)             # 输出:3.14159

6. __name__变量

__name__ 是Python的特殊变量,用于判断模块是被直接运行还是被导入。

python 复制代码
# mymodule.py
def main():
    print("这是主函数")

if __name__ == "__main__":
    # 只有直接运行此文件时才会执行
    main()
    print("直接运行mymodule.py")
else:
    # 被其他文件导入时不会执行
    print("mymodule.py被导入")

💡 提示:

  • 直接运行文件时,__name__ 等于 "__main__"
  • 被导入时,__name__ 等于模块名

二、创建自己的模块

1. 创建简单模块

python 复制代码
# calculator.py
"""
计算器模块
提供基本的数学运算功能
"""

def add(a, b):
    """加法"""
    return a + b

def subtract(a, b):
    """减法"""
    return a - b

def multiply(a, b):
    """乘法"""
    return a * b

def divide(a, b):
    """除法"""
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b

# 测试代码
if __name__ == "__main__":
    print("测试计算器模块")
    print(f"2 + 3 = {add(2, 3)}")
    print(f"5 - 2 = {subtract(5, 2)}")
    print(f"4 * 3 = {multiply(4, 3)}")
    print(f"6 / 2 = {divide(6, 2)}")

2. 模块的文档字符串

python 复制代码
"""
学生管理模块

提供学生信息的增删改查功能。

作者:全栈弄潮儿
版本:1.0
日期:2024-01-01
"""

class Student:
    """学生类"""
    
    def __init__(self, student_id, name, age):
        self.student_id = student_id
        self.name = name
        self.age = age
    
    def info(self):
        """显示学生信息"""
        print(f"学号:{self.student_id},姓名:{self.name},年龄:{self.age}")

def create_student(student_id, name, age):
    """创建学生对象"""
    return Student(student_id, name, age)

3. 模块的__all__变量

__all__ 用于控制 from module import * 时导入的内容。

python 复制代码
# mymodule.py
__all__ = ["public_function", "PublicClass"]

def public_function():
    """公开函数"""
    pass

def _private_function():
    """私有函数(不会被import *导入)"""
    pass

class PublicClass:
    """公开类"""
    pass

class _PrivateClass:
    """私有类(不会被import *导入)"""
    pass

4. 模块搜索路径

Python按照以下顺序搜索模块:

  1. 当前目录
  2. PYTHONPATH环境变量中的目录
  3. 默认路径(安装时设置的目录)
python 复制代码
import sys

# 查看模块搜索路径
for path in sys.path:
    print(path)

# 添加搜索路径
sys.path.append("/path/to/your/module")

三、包的组织

1. 什么是包

包是包含多个模块的目录,用于组织相关的模块。

markdown 复制代码
my_package/
    __init__.py
    module1.py
    module2.py
    subpackage/
        __init__.py
        module3.py

2. 创建包

markdown 复制代码
# 目录结构
math_package/
    __init__.py
    basic.py
    advanced.py
python 复制代码
# math_package/__init__.py
"""
数学包
提供基本和高级数学运算功能
"""

from .basic import add, subtract
from .advanced import power, sqrt

__all__ = ["add", "subtract", "power", "sqrt"]
__version__ = "1.0.0"
python 复制代码
# math_package/basic.py
"""基本数学运算"""

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

def subtract(a, b):
    return a - b
python 复制代码
# math_package/advanced.py
"""高级数学运算"""

import math

def power(base, exponent):
    return base ** exponent

def sqrt(x):
    return math.sqrt(x)
python 复制代码
# 使用包
import math_package

print(math_package.add(2, 3))       # 输出:5
print(math_package.sqrt(16))        # 输出:4.0

# 导入特定模块
from math_package import basic
print(basic.add(2, 3))

# 导入特定函数
from math_package.advanced import power
print(power(2, 10))  # 输出:1024

3. init.py的作用

__init__.py 文件有以下作用:

  1. 标识目录为Python包
  2. 初始化包
  3. 控制包的公开接口
python 复制代码
# my_package/__init__.py

# 1. 设置包的版本
__version__ = "1.0.0"

# 2. 导入子模块
from . import module1
from . import module2

# 3. 设置公开接口
__all__ = ["module1", "module2", "public_function"]

# 4. 初始化代码
print("包被导入")

def public_function():
    """公开函数"""
    pass

4. 相对导入和绝对导入

python 复制代码
# 目录结构
package/
    __init__.py
    module1.py
    subpackage/
        __init__.py
        module2.py

# package/subpackage/module2.py

# 绝对导入(推荐)
from package import module1

# 相对导入
from .. import module1      # 导入父包中的module1
from . import module3       # 导入同包中的module3

💡 提示:

  • 绝对导入更清晰,推荐使用
  • 相对导入只在包内部使用

四、pip安装第三方库

1. 什么是pip

pip 是Python的包管理工具,用于安装和管理第三方库。

bash 复制代码
# 查看pip版本
pip --version

# 升级pip
python -m pip install --upgrade pip

2. 安装第三方库

bash 复制代码
# 安装单个库
pip install requests

# 安装指定版本
pip install requests==2.28.0

# 安装多个库
pip install requests numpy pandas

# 从requirements.txt安装
pip install -r requirements.txt

3. requirements.txt

requirements.txt 文件用于记录项目依赖。

txt 复制代码
# requirements.txt
requests==2.28.0
numpy>=1.21.0
pandas>=1.3.0
flask>=2.0.0
bash 复制代码
# 生成requirements.txt
pip freeze > requirements.txt

# 从requirements.txt安装
pip install -r requirements.txt

4. 常用第三方库

bash 复制代码
# 数据处理
pip install numpy pandas

# 网络请求
pip install requests

# Web开发
pip install flask django

# 数据可视化
pip install matplotlib seaborn

# 机器学习
pip install scikit-learn tensorflow pytorch

# 爬虫
pip install beautifulsoup4 scrapy

# 数据库
pip install sqlalchemy pymysql

5. 虚拟环境

虚拟环境可以为每个项目创建独立的Python环境。

bash 复制代码
# 创建虚拟环境
python -m venv myenv

# 激活虚拟环境
# Windows
myenv\Scripts\activate

# macOS/Linux
source myenv/bin/activate

# 退出虚拟环境
deactivate

# 在虚拟环境中安装包
pip install requests

💡 提示:

  • 每个项目使用独立的虚拟环境
  • 避免不同项目的依赖冲突
  • 方便部署和分享

五、常用标准库

1. os模块

python 复制代码
import os

# 当前工作目录
print(os.getcwd())

# 切换目录
os.chdir("/path/to/dir")

# 列出目录内容
print(os.listdir("."))

# 创建目录
os.mkdir("new_dir")

# 删除目录
os.rmdir("new_dir")

# 删除文件
os.remove("file.txt")

# 路径操作
path = os.path.join("folder", "subfolder", "file.txt")
print(path)

print(os.path.exists("file.txt"))
print(os.path.isfile("file.txt"))
print(os.path.isdir("folder"))

2. sys模块

python 复制代码
import sys

# Python版本
print(sys.version)

# 命令行参数
print(sys.argv)

# 退出程序
sys.exit(0)

# 模块搜索路径
print(sys.path)

# 标准输入输出
sys.stdout.write("Hello\n")
sys.stderr.write("Error\n")

3. datetime模块

python 复制代码
from datetime import datetime, timedelta

# 当前时间
now = datetime.now()
print(now)

# 格式化时间
print(now.strftime("%Y-%m-%d %H:%M:%S"))

# 解析时间
dt = datetime.strptime("2024-01-01 12:00:00", "%Y-%m-%d %H:%M:%S")
print(dt)

# 时间计算
tomorrow = now + timedelta(days=1)
print(tomorrow)

# 时间差
delta = tomorrow - now
print(delta.days)

4. json模块

python 复制代码
import json

# Python对象转JSON字符串
data = {"name": "小明", "age": 20}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)

# JSON字符串转Python对象
parsed = json.loads(json_str)
print(parsed)

# 写入JSON文件
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

# 读取JSON文件
with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)
    print(data)

5. random模块

python 复制代码
import random

# 随机整数
print(random.randint(1, 10))

# 随机浮点数
print(random.random())

# 随机选择
fruits = ["苹果", "香蕉", "橙子"]
print(random.choice(fruits))

# 随机打乱
random.shuffle(fruits)
print(fruits)

# 生成随机样本
print(random.sample(range(100), 5))

六、实战练习

练习1:创建工具模块

python 复制代码
# utils.py
"""
工具模块
提供常用的工具函数
"""

import os
import json
from datetime import datetime

def ensure_dir(path):
    """确保目录存在"""
    if not os.path.exists(path):
        os.makedirs(path)

def load_json(filepath):
    """加载JSON文件"""
    with open(filepath, "r", encoding="utf-8") as f:
        return json.load(f)

def save_json(data, filepath):
    """保存JSON文件"""
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def get_timestamp():
    """获取当前时间戳"""
    return datetime.now().strftime("%Y%m%d_%H%M%S")

def format_size(size_bytes):
    """格式化文件大小"""
    for unit in ["B", "KB", "MB", "GB"]:
        if size_bytes < 1024:
            return f"{size_bytes:.2f} {unit}"
        size_bytes /= 1024
    return f"{size_bytes:.2f} TB"

# 测试
if __name__ == "__main__":
    print("测试工具模块")
    print(f"时间戳:{get_timestamp()}")
    print(f"文件大小:{format_size(1024 * 1024 * 5)}")

练习2:创建配置管理包

arduino 复制代码
config_manager/
    __init__.py
    config.py
    validator.py
python 复制代码
# config_manager/__init__.py
"""
配置管理包
"""

from .config import Config
from .validator import validate_config

__all__ = ["Config", "validate_config"]
__version__ = "1.0.0"
python 复制代码
# config_manager/config.py
"""
配置类
"""

import json
import os

class Config:
    """配置管理类"""
    
    def __init__(self, config_file="config.json"):
        self.config_file = config_file
        self.data = {}
        self.load()
    
    def load(self):
        """加载配置"""
        if os.path.exists(self.config_file):
            with open(self.config_file, "r", encoding="utf-8") as f:
                self.data = json.load(f)
    
    def save(self):
        """保存配置"""
        with open(self.config_file, "w", encoding="utf-8") as f:
            json.dump(self.data, f, ensure_ascii=False, indent=2)
    
    def get(self, key, default=None):
        """获取配置项"""
        return self.data.get(key, default)
    
    def set(self, key, value):
        """设置配置项"""
        self.data[key] = value
        self.save()
python 复制代码
# config_manager/validator.py
"""
配置验证器
"""

def validate_config(config_data, schema):
    """验证配置是否符合schema"""
    errors = []
    
    for key, rules in schema.items():
        if rules.get("required") and key not in config_data:
            errors.append(f"缺少必填项:{key}")
            continue
        
        if key in config_data:
            value = config_data[key]
            expected_type = rules.get("type")
            
            if expected_type and not isinstance(value, expected_type):
                errors.append(f"{key}类型错误,期望{expected_type}")
    
    return errors

练习3:使用第三方库

python 复制代码
# 使用requests库
import requests

def fetch_data(url):
    """获取网络数据"""
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        print(f"请求失败:{e}")
        return None

# 使用pandas库
import pandas as pd

def analyze_csv(filepath):
    """分析CSV文件"""
    df = pd.read_csv(filepath)
    
    print(f"数据形状:{df.shape}")
    print(f"列名:{df.columns.tolist()}")
    print(f"统计信息:\n{df.describe()}")
    
    return df

# 使用matplotlib库
import matplotlib.pyplot as plt

def plot_data(data):
    """绘制数据图表"""
    plt.figure(figsize=(10, 6))
    plt.plot(data)
    plt.title("数据趋势图")
    plt.xlabel("X轴")
    plt.ylabel("Y轴")
    plt.grid(True)
    plt.savefig("plot.png")
    plt.show()

七、常见问题与排错

问题1:ModuleNotFoundError

原因 :找不到模块 解决方法:检查模块路径和名称

python 复制代码
# ❌ 错误
import mymodule  # ModuleNotFoundError

# ✅ 解决方法1:确保模块在当前目录或PYTHONPATH中
# ✅ 解决方法2:添加路径
import sys
sys.path.append("/path/to/module")
import mymodule

问题2:循环导入

原因 :两个模块互相导入 解决方法:重构代码,避免循环依赖

python 复制代码
# ❌ 错误:循环导入
# a.py
import b

# b.py
import a

# ✅ 解决方法:重构代码结构
# 将共同依赖的代码提取到第三个模块

问题3:pip安装失败

原因 :网络问题或源不可用 解决方法:使用国内镜像源

bash 复制代码
# 使用清华镜像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests

# 永久设置镜像
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

八、本篇小结

今天,我们完成了以下学习内容:

  1. 导入模块:

    • import module 导入整个模块
    • from module import name 导入特定内容
    • as 起别名
    • __name__ 判断模块运行方式
  2. 创建自己的模块:

    • 一个.py文件就是一个模块
    • 使用文档字符串说明模块
    • 使用 __all__ 控制公开接口
  3. 包的组织:

    • 包是包含多个模块的目录
    • __init__.py 标识和初始化包
    • 相对导入和绝对导入
  4. pip安装第三方库:

    • pip install 安装库
    • requirements.txt 管理依赖
    • 虚拟环境隔离项目

请记住这三个结论:

  1. 模块是代码组织的基本单位:一个.py文件就是一个模块
  2. 包用于组织相关模块 :包含 __init__.py 的目录就是包
  3. pip是Python的包管理器:用于安装和管理第三方库

下期预告

在第14期中,我们将学习Python的装饰器和生成器,包括:

  • 装饰器的概念和语法
  • 带参数的装饰器
  • 生成器的使用
  • yield关键字

敬请期待!


✍坚持原创,求关注,点赞,收藏

相关推荐
Thneonl1 小时前
ClickHouse UPDATE:一秒返回,三小时才生效
数据库·后端
2401_885885042 小时前
芬兰语音通知接口怎样对接?语音提醒接入流程
android·前端·python·php·语音识别
铁皮饭盒2 小时前
这6个小模型各有绝活, 且都可cpu/浏览器端运行
前端·后端
Dev _2 小时前
Python解释器安装在系统级目录导致命令行用户‌没有权限‌向该目录写入文件
开发语言·python
qq_406981032 小时前
大白话rust系列08 当变量遮蔽遇上引用,探究变量遮蔽的本质
开发语言·后端·rust
喵了几个咪3 小时前
GoWind ShortPlay 拆解:不用模型的推荐闭环——埋点回流、三路召回与已看去重
开发语言·后端·微服务·golang·gowind
SimonKing3 小时前
又找到一个纯Java的OCR项目,识别的格式还挺多
java·后端·程序员
Dev _3 小时前
PyCharm旧进程仍在后台运行,导致新实例无法启动或连接
ide·python·pycharm
程序猿DD3 小时前
OctaFuse Gateway 2.17.0:新增维护模式、请求日志汇总、DashScope 语音路由拆分
后端