5、Python模块与包 - 代码组织与重用

4 阅读7分钟

Python模块与包 - 代码组织与重用

1. 模块与包概述

作为Java开发者,您已经熟悉了使用包和类来组织代码的方式。Python也提供了类似的机制,通过模块和包来组织和重用代码。

2. Python模块

什么是模块?

模块是包含Python定义和语句的文件。文件名就是模块名加上.py后缀。模块允许您以逻辑方式组织Python代码,使其更易于理解和使用。

创建模块

创建模块非常简单,只需创建一个.py文件:

# math_utils.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

PI = 3.14159

导入模块

有多种方式可以导入模块:

# 导入整个模块
import math_utils

result = math_utils.add(10, 5)
print(result)  # 输出: 15
print(math_utils.PI)  # 输出: 3.14159

# 导入特定函数或变量
from math_utils import add, subtract, PI

result = add(10, 5)
print(result)  # 输出: 15
print(PI)  # 输出: 3.14159

# 导入所有内容(不推荐,可能导致命名冲突)
from math_utils import *

result = multiply(10, 5)
print(result)  # 输出: 50

# 使用别名
import math_utils as mu

result = mu.divide(10, 2)
print(result)  # 输出: 5.0

模块搜索路径

当导入模块时,Python会在以下位置按顺序查找模块:

  1. 当前目录
  2. 环境变量PYTHONPATH中的目录
  3. 标准库目录
  4. 任何.pth文件中指定的路径

可以通过sys.path查看当前的搜索路径:

import sys
print(sys.path)

模块的__name__属性

每个模块都有一个__name__属性。如果模块作为主程序运行,则__name__的值为"__main__";如果模块被导入,则__name__的值为模块名。

这允许您编写既可以作为模块导入,又可以作为独立程序运行的代码:

# calculator.py
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

if __name__ == "__main__":
    # 这部分代码只在直接运行该文件时执行
    print("计算器模块正在作为主程序运行")
    print(f"10 + 5 = {add(10, 5)}")
    print(f"10 - 5 = {subtract(10, 5)}")
else:
    # 这部分代码在导入该模块时执行
    print("计算器模块已被导入")

3. Python包

包结构图

graph TD
    A[myproject] --> B[mypackage]
    B --> C[__init__.py]
    B --> D[module1.py]
    B --> E[module2.py]
    B --> F[subpackage]
    F --> G[__init__.py]
    F --> H[submodule1.py]
    F --> I[submodule2.py]
    
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:1px
    style F fill:#bbf,stroke:#333,stroke-width:1px
    style C fill:#dfd,stroke:#333,stroke-width:1px
    style D fill:#dfd,stroke:#333,stroke-width:1px
    style E fill:#dfd,stroke:#333,stroke-width:1px
    style G fill:#dfd,stroke:#333,stroke-width:1px
    style H fill:#dfd,stroke:#333,stroke-width:1px
    style I fill:#dfd,stroke:#333,stroke-width:1px

什么是包?

包是一种通过使用"带点号的模块名"来构建Python模块命名空间的方式。例如,模块名A.B表示包A中的子模块B

创建包

创建包需要:

  1. 创建一个目录
  2. 在目录中创建一个__init__.py文件(在Python 3.3+中可选,但建议包含)
  3. 在目录中添加模块文件

例如,创建一个名为mymath的包:

mymath/
    __init__.py
    basic.py
    advanced.py

__init__.py文件可以为空,也可以包含初始化代码:

# mymath/__init__.py
print("初始化mymath包")

# 可以在这里导入子模块,使它们在导入包时可用
from . import basic
from . import advanced

basic.pyadvanced.py包含各自的函数:

# mymath/basic.py
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b
# mymath/advanced.py
import math

def square_root(x):
    return math.sqrt(x)

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

导入包

可以通过多种方式导入包中的模块:

# 导入包
import mymath

# 导入包中的特定模块
import mymath.basic
result = mymath.basic.add(10, 5)
print(result)  # 输出: 15

# 从包中导入特定模块
from mymath import advanced
result = advanced.square_root(16)
print(result)  # 输出: 4.0

# 从包的模块中导入特定函数
from mymath.basic import add, subtract
result = add(10, 5)
print(result)  # 输出: 15

相对导入

在包内的模块之间,可以使用相对导入:

# mymath/advanced.py
from . import basic  # 导入同一包中的basic模块
from .. import other_package  # 导入父包中的other_package包

4. 标准库模块

Python标准库包含了大量有用的模块。以下是一些常用的标准库模块:

os模块 - 操作系统接口

import os

# 获取当前工作目录
current_dir = os.getcwd()
print(current_dir)

# 列出目录内容
files = os.listdir('.')
print(files)

# 创建目录
os.mkdir('new_directory')

# 删除文件
os.remove('old_file.txt')

# 环境变量
home = os.environ.get('HOME')
print(home)

sys模块 - 系统特定参数和函数

import sys

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

# Python版本
print(sys.version)

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

# 标准输入输出
sys.stdout.write('Hello\n')
name = sys.stdin.readline().strip()

datetime模块 - 日期和时间

from datetime import datetime, date, time, timedelta

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

# 创建日期
today = date.today()
print(today)

# 日期格式化
formatted = now.strftime('%Y-%m-%d %H:%M:%S')
print(formatted)

# 日期计算
tomorrow = today + timedelta(days=1)
print(tomorrow)

json模块 - JSON编码和解码

import json

# Python对象转JSON
data = {
    'name': '张三',
    'age': 30,
    'city': '北京',
    'skills': ['Python', 'Java', 'SQL']
}

json_str = json.dumps(data, ensure_ascii=False)
print(json_str)

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

# JSON转Python对象
parsed = json.loads(json_str)
print(parsed['name'])

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

re模块 - 正则表达式

import re

# 匹配模式
text = "联系方式:电话13812345678,邮箱example@email.com"
phone_pattern = r'1\d{10}'
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'

# 查找所有匹配
phones = re.findall(phone_pattern, text)
emails = re.findall(email_pattern, text)

print(phones)  # 输出: ['13812345678']
print(emails)  # 输出: ['example@email.com']

# 替换
new_text = re.sub(phone_pattern, '1xx xxxx xxxx', text)
print(new_text)

5. 第三方库

Python生态系统中有大量优质的第三方库。使用pip(Python的包管理器)可以轻松安装这些库。

安装第三方库

# 安装单个库
pip install requests

# 安装特定版本
pip install numpy==1.19.5

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

常用第三方库

  1. requests - HTTP请求

    import requests
    
    response = requests.get('https://api.github.com')
    data = response.json()
    print(data)
    
  2. NumPy - 科学计算

    import numpy as np
    
    arr = np.array([1, 2, 3, 4, 5])
    print(arr.mean())
    print(arr.std())
    
  3. pandas - 数据分析

    import pandas as pd
    
    df = pd.DataFrame({
        'Name': ['Alice', 'Bob', 'Charlie'],
        'Age': [25, 30, 35],
        'City': ['New York', 'Paris', 'London']
    })
    
    print(df)
    print(df.describe())
    
  4. matplotlib - 数据可视化

    import matplotlib.pyplot as plt
    
    x = [1, 2, 3, 4, 5]
    y = [1, 4, 9, 16, 25]
    
    plt.plot(x, y)
    plt.xlabel('X轴')
    plt.ylabel('Y轴')
    plt.title('简单图表')
    plt.show()
    

6. 虚拟环境

虚拟环境是Python的一个重要特性,允许您为不同项目创建隔离的Python环境,避免依赖冲突。

创建虚拟环境

# Python 3.3+
python -m venv myenv

# 激活虚拟环境
# Windows
myenv\Scripts\activate
# macOS/Linux
source myenv/bin/activate

# 停用虚拟环境
deactivate

使用conda创建虚拟环境

如果您使用Anaconda或Miniconda:

# 创建环境
conda create -n myenv python=3.8

# 激活环境
conda activate myenv

# 停用环境
conda deactivate

7. 项目结构

一个典型的Python项目结构可能如下:

project_name/
│
├── README.md           # 项目说明
├── requirements.txt    # 依赖列表
├── setup.py            # 安装脚本
│
├── project_name/       # 主包
│   ├── __init__.py
│   ├── module1.py
│   ├── module2.py
│   └── subpackage/
│       ├── __init__.py
│       └── module3.py
│
├── tests/              # 测试代码
│   ├── __init__.py
│   ├── test_module1.py
│   └── test_module2.py
│
└── docs/               # 文档
    └── index.md

8. 与Java对比

JavaPython说明
包(package)包(package)Python包是包含__init__.py的目录
类(class)模块(module)Python模块是.py文件,可以包含函数、类等
import语句import语句Python的import更灵活,支持部分导入
JAR文件wheel/eggPython的分发格式
Maven/Gradlepip/conda包管理工具
Maven CentralPyPI包存储库

9. 练习:创建和使用模块

练习1:创建一个简单的模块和包

  1. 创建一个名为utils的包,包含以下模块:

    • string_utils.py:包含字符串处理函数
    • file_utils.py:包含文件操作函数
  2. 在另一个脚本中导入并使用这些模块

# utils/__init__.py
print("初始化utils包")

# utils/string_utils.py
def reverse_string(s):
    return s[::-1]

def count_vowels(s):
    vowels = "aeiouAEIOU"
    return sum(1 for char in s if char in vowels)

# utils/file_utils.py
def read_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        print(f"读取文件出错: {e}")
        return None

def write_file(filename, content):
    try:
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(content)
        return True
    except Exception as e:
        print(f"写入文件出错: {e}")
        return False

# main.py
from utils import string_utils, file_utils

# 使用string_utils
text = "Hello, Python!"
print(f"原始字符串: {text}")
print(f"反转字符串: {string_utils.reverse_string(text)}")
print(f"元音字母数: {string_utils.count_vowels(text)}")

# 使用file_utils
file_utils.write_file("test.txt", text)
content = file_utils.read_file("test.txt")
print(f"读取的文件内容: {content}")

10. 今日总结

  • Python使用模块和包来组织代码,提高可重用性和可维护性
  • 模块是包含Python代码的.py文件
  • 包是包含__init__.py文件的目录,可以包含多个模块
  • Python标准库提供了大量有用的模块,如ossysdatetimejson
  • 可以使用pip安装第三方库,扩展Python的功能
  • 虚拟环境允许为不同项目创建隔离的Python环境
  • Python的模块系统比Java的包系统更灵活,支持部分导入和相对导入

11. 明日预告

明天我们将学习Python的文件操作和异常处理,包括如何读写文件、处理不同文件格式以及如何优雅地处理错误和异常。