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会在以下位置按顺序查找模块:
- 当前目录
- 环境变量PYTHONPATH中的目录
- 标准库目录
- 任何
.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
。
创建包
创建包需要:
- 创建一个目录
- 在目录中创建一个
__init__.py
文件(在Python 3.3+中可选,但建议包含) - 在目录中添加模块文件
例如,创建一个名为mymath
的包:
mymath/
__init__.py
basic.py
advanced.py
__init__.py
文件可以为空,也可以包含初始化代码:
# mymath/__init__.py
print("初始化mymath包")
# 可以在这里导入子模块,使它们在导入包时可用
from . import basic
from . import advanced
basic.py
和advanced.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
常用第三方库
-
requests - HTTP请求
import requests response = requests.get('https://api.github.com') data = response.json() print(data)
-
NumPy - 科学计算
import numpy as np arr = np.array([1, 2, 3, 4, 5]) print(arr.mean()) print(arr.std())
-
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())
-
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对比
Java | Python | 说明 |
---|---|---|
包(package) | 包(package) | Python包是包含__init__.py 的目录 |
类(class) | 模块(module) | Python模块是.py 文件,可以包含函数、类等 |
import语句 | import语句 | Python的import更灵活,支持部分导入 |
JAR文件 | wheel/egg | Python的分发格式 |
Maven/Gradle | pip/conda | 包管理工具 |
Maven Central | PyPI | 包存储库 |
9. 练习:创建和使用模块
练习1:创建一个简单的模块和包
-
创建一个名为
utils
的包,包含以下模块:string_utils.py
:包含字符串处理函数file_utils.py
:包含文件操作函数
-
在另一个脚本中导入并使用这些模块
# 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标准库提供了大量有用的模块,如
os
、sys
、datetime
、json
等 - 可以使用
pip
安装第三方库,扩展Python的功能 - 虚拟环境允许为不同项目创建隔离的Python环境
- Python的模块系统比Java的包系统更灵活,支持部分导入和相对导入
11. 明日预告
明天我们将学习Python的文件操作和异常处理,包括如何读写文件、处理不同文件格式以及如何优雅地处理错误和异常。