在Python编程中,模块和包就像乐高积木的盒子------它们帮助你把相关的代码组织在一起,让大型项目变得井然有序。今天,我们来学习如何将Python代码组织成模块和包,构建可维护的代码结构!
引入:为什么需要模块和包?
想象一下,你正在开发一个电商网站:
- 需要处理用户认证
- 需要管理商品
- 需要处理订单
- 需要与数据库交互
如果不使用模块和包,你可能会有一个巨大的文件,里面包含所有功能,这样的代码:
- 难以阅读和维护
- 难以多人协作开发
- 难以重用特定功能
使用模块和包,你可以:
- 将用户认证代码放在
auth.py模块中 - 将商品管理代码放在
products.py模块中 - 将订单处理代码放在
orders.py模块中 - 将所有相关模块组织在
ecommerce包中
这就是模块化和代码组织的魅力!
一、模块基础:创建和使用模块
1.1 什么是模块?
模块 就是一个包含Python代码的 .py 文件。模块可以包含:
- 函数
- 类
- 变量
- 可执行代码
1.2 创建第一个模块
python
# 创建一个名为 calculator.py 的模块
print("=== 创建和使用模块 ===\n")
# calculator.py 的内容如下:
"""
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):
"""
返回两个数的商
如果除数为0,返回None
"""
if b == 0:
return None
return a / b
# 模块级别的变量
PI = 3.141592653589793
VERSION = "1.0.0"
# 模块级别的函数
def get_version():
"""返回模块版本"""
return VERSION
# 模块测试代码(通常放在最后)
if __name__ == "__main__":
# 只有当直接运行这个模块时才执行
print("测试计算器模块:")
print(f"5 + 3 = {add(5, 3)}")
print(f"5 - 3 = {subtract(5, 3)}")
print(f"5 * 3 = {multiply(5, 3)}")
print(f"5 / 3 = {divide(5, 3):.2f}")
print(f"5 / 0 = {divide(5, 0)}")
print(f"PI = {PI}")
print(f"版本:{get_version()}")
1.3 使用模块
python
# main.py - 使用计算器模块
print("=== 使用模块 ===\n")
# 方法1:导入整个模块
import calculator
print("方法1:导入整个模块")
print(f"5 + 3 = {calculator.add(5, 3)}")
print(f"PI = {calculator.PI}")
print(f"版本:{calculator.get_version()}\n")
# 方法2:导入特定函数/变量
from calculator import add, subtract, PI
print("方法2:导入特定函数/变量")
print(f"5 + 3 = {add(5, 3)}")
print(f"5 - 3 = {subtract(5, 3)}")
print(f"PI = {PI}\n")
# 方法3:导入所有内容(不推荐)
from calculator import *
print("方法3:导入所有内容")
print(f"5 * 3 = {multiply(5, 3)}")
print(f"5 / 3 = {divide(5, 3):.2f}\n")
# 方法4:给模块起别名
import calculator as calc
print("方法4:给模块起别名")
print(f"calc.add(5, 3) = {calc.add(5, 3)}")
print(f"calc.VERSION = {calc.VERSION}\n")
# 方法5:给函数起别名
from calculator import add as addition
print("方法5:给函数起别名")
print(f"addition(5, 3) = {addition(5, 3)}")
print("\n=== 查看模块信息 ===")
print(f"模块名:{calculator.__name__}")
print(f"文件位置:{calculator.__file__}")
print(f"文档字符串:{calculator.__doc__}")
print(f"模块中的所有名称:{dir(calculator)[:10]}...") # 只显示前10个
1.4 模块搜索路径
python
print("\n=== Python模块搜索路径 ===")
import sys
print("Python搜索模块的路径:")
for i, path in enumerate(sys.path, 1):
print(f"{i:2}. {path}")
print("\n=== 自定义模块搜索路径 ===")
# 添加自定义路径到模块搜索路径
import os
# 创建自定义模块目录
custom_dir = "my_modules"
if not os.path.exists(custom_dir):
os.makedirs(custom_dir)
# 创建一个简单的模块
module_content = '''
def hello():
return "来自自定义模块的问候!"
def add(a, b):
return a + b
'''
# 将模块保存到自定义目录
with open(os.path.join(custom_dir, "mymodule.py"), "w") as f:
f.write(module_content)
# 添加自定义目录到搜索路径
sys.path.append(os.path.abspath(custom_dir))
# 现在可以导入自定义模块
try:
import mymodule
print(f"成功导入自定义模块:{mymodule.hello()}")
print(f"mymodule.add(5, 3) = {mymodule.add(5, 3)}")
except ImportError as e:
print(f"导入失败:{e}")
print("\n=== 动态导入模块 ===")
# 有时我们需要在运行时决定导入哪个模块
module_name = "calculator" # 可以是变量
# 方法1:使用__import__
print("方法1:使用 __import__")
try:
calc_module = __import__(module_name)
print(f"导入成功:{calc_module.add(5, 3)}")
except ImportError:
print(f"无法导入模块:{module_name}")
# 方法2:使用importlib(推荐)
print("\n方法2:使用 importlib")
import importlib
try:
calc_module = importlib.import_module(module_name)
print(f"导入成功:{calc_module.subtract(5, 3)}")
except ImportError:
print(f"无法导入模块:{module_name}")
二、包:组织模块的容器
2.1 什么是包?
包 是一个包含多个模块的目录。包必须包含一个特殊的文件:__init__.py(Python 3.3+ 中可以是空文件,但推荐包含内容)。
2.2 创建包的结构
python
ecommerce/ # 包目录
├── __init__.py # 包初始化文件
├── products.py # 商品模块
├── orders.py # 订单模块
├── auth.py # 认证模块
├── database/ # 子包
│ ├── __init__.py
│ ├── connection.py
│ └── models.py
└── utils/ # 另一个子包
├── __init__.py
├── validators.py
└── helpers.py
2.3 创建包和子包
python
# 创建ecommerce包及其模块
print("=== 创建和使用包 ===")
# 首先创建目录结构
import os
import shutil
# 清理旧的测试目录
if os.path.exists("ecommerce"):
shutil.rmtree("ecommerce")
# 创建目录结构
os.makedirs("ecommerce/database")
os.makedirs("ecommerce/utils")
# 创建 __init__.py 文件
print("创建包和子包...")
# ecommerce/__init__.py
init_content = '''
"""
ecommerce包 - 电子商务系统
这个包包含电子商务网站的核心功能。
"""
__version__ = "1.0.0"
__author__ = "Python开发者"
# 导入包级别的功能
from .products import Product
from .orders import Order
from .auth import authenticate
# 包级别的变量
SITE_NAME = "我的电商网站"
def get_version():
"""返回包版本"""
return __version__
'''
with open("ecommerce/__init__.py", "w") as f:
f.write(init_content)
# ecommerce/products.py
products_content = '''
class Product:
"""商品类"""
def __init__(self, name, price, category):
self.name = name
self.price = price
self.category = category
def display_info(self):
"""显示商品信息"""
return f"{self.name} - ¥{self.price:.2f} ({self.category})"
def apply_discount(self, discount_percent):
"""应用折扣"""
discounted_price = self.price * (1 - discount_percent / 100)
return discounted_price
def create_product(name, price, category):
"""创建商品"""
return Product(name, price, category)
def calculate_total(products):
"""计算商品总价"""
return sum(product.price for product in products)
'''
with open("ecommerce/products.py", "w") as f:
f.write(products_content)
# ecommerce/orders.py
orders_content = '''
class Order:
"""订单类"""
def __init__(self, order_id, customer, products):
self.order_id = order_id
self.customer = customer
self.products = products
self.status = "pending"
def calculate_total(self):
"""计算订单总额"""
return sum(product.price for product in self.products)
def update_status(self, new_status):
"""更新订单状态"""
valid_statuses = ["pending", "processing", "shipped", "delivered", "cancelled"]
if new_status in valid_statuses:
self.status = new_status
return True
return False
def display_order(self):
"""显示订单信息"""
total = self.calculate_total()
return f"订单 #{self.order_id} - 客户: {self.customer}, 总额: ¥{total:.2f}, 状态: {self.status}"
'''
with open("ecommerce/orders.py", "w") as f:
f.write(orders_content)
# ecommerce/auth.py
auth_content = '''
def authenticate(username, password):
"""用户认证"""
# 这里应该是数据库查询,这里用硬编码演示
users = {
"admin": "admin123",
"user1": "password1",
"user2": "password2"
}
if username in users and users[username] == password:
return True, f"欢迎回来,{username}!"
else:
return False, "用户名或密码错误"
def register(username, password, email):
"""用户注册"""
# 这里应该有数据库操作,这里只是演示
return True, f"用户 {username} 注册成功!"
def logout(username):
"""用户退出"""
return f"用户 {username} 已退出登录"
'''
with open("ecommerce/auth.py", "w") as f:
f.write(auth_content)
# ecommerce/database/__init__.py
db_init_content = '''
"""
数据库子包
"""
from .connection import DatabaseConnection
from .models import User, ProductModel
__all__ = ['DatabaseConnection', 'User', 'ProductModel']
'''
with open("ecommerce/database/__init__.py", "w") as f:
f.write(db_init_content)
# ecommerce/database/connection.py
connection_content = '''
class DatabaseConnection:
"""数据库连接类"""
def __init__(self, host, port, database):
self.host = host
self.port = port
self.database = database
self.connected = False
def connect(self):
"""连接数据库"""
self.connected = True
return f"已连接到 {self.host}:{self.port}/{self.database}"
def disconnect(self):
"""断开数据库连接"""
self.connected = False
return "数据库连接已断开"
def execute_query(self, query):
"""执行查询"""
if self.connected:
return f"执行查询: {query}"
else:
return "错误:数据库未连接"
'''
with open("ecommerce/database/connection.py", "w") as f:
f.write(connection_content)
# ecommerce/database/models.py
models_content = '''
class User:
"""用户模型"""
def __init__(self, user_id, username, email):
self.user_id = user_id
self.username = username
self.email = email
def to_dict(self):
"""转换为字典"""
return {
'user_id': self.user_id,
'username': self.username,
'email': self.email
}
class ProductModel:
"""商品模型"""
def __init__(self, product_id, name, price, stock):
self.product_id = product_id
self.name = name
self.price = price
self.stock = stock
def is_available(self):
"""检查是否有库存"""
return self.stock > 0
def update_stock(self, quantity):
"""更新库存"""
if self.stock + quantity >= 0:
self.stock += quantity
return True
return False
'''
with open("ecommerce/database/models.py", "w") as f:
f.write(models_content)
# ecommerce/utils/__init__.py
utils_init_content = '''
"""
工具函数子包
"""
from .validators import validate_email, validate_phone
from .helpers import format_price, generate_id
__all__ = ['validate_email', 'validate_phone', 'format_price', 'generate_id']
'''
with open("ecommerce/utils/__init__.py", "w") as f:
f.write(utils_init_content)
# ecommerce/utils/validators.py
validators_content = '''
import re
def validate_email(email):
"""验证邮箱格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
def validate_phone(phone):
"""验证手机号格式(中国)"""
pattern = r'^1[3-9]\d{9}$'
return bool(re.match(pattern, phone))
def validate_password(password):
"""验证密码强度"""
if len(password) < 8:
return False, "密码至少8位"
if not any(c.isupper() for c in password):
return False, "密码必须包含大写字母"
if not any(c.islower() for c in password):
return False, "密码必须包含小写字母"
if not any(c.isdigit() for c in password):
return False, "密码必须包含数字"
return True, "密码强度足够"
'''
with open("ecommerce/utils/validators.py", "w") as f:
f.write(validators_content)
# ecommerce/utils/helpers.py
helpers_content = '''
import random
import string
from datetime import datetime
def format_price(price):
"""格式化价格"""
return f"¥{price:,.2f}"
def generate_id(prefix="", length=8):
"""生成随机ID"""
chars = string.ascii_uppercase + string.digits
random_part = ''.join(random.choices(chars, k=length))
return f"{prefix}{random_part}"
def get_current_timestamp():
"""获取当前时间戳"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def truncate_text(text, max_length=50):
"""截断文本"""
if len(text) <= max_length:
return text
return text[:max_length] + "..."
'''
with open("ecommerce/utils/helpers.py", "w") as f:
f.write(helpers_content)
print("包结构创建完成!\n")
# 现在让我们使用这个包
print("=== 使用包 ===")
# 方法1:导入整个包
import ecommerce
print(f"包版本:{ecommerce.get_version()}")
print(f"网站名称:{ecommerce.SITE_NAME}\n")
# 方法2:从包中导入特定模块
from ecommerce import products
# 使用products模块
product1 = products.create_product("Python编程书", 89.90, "图书")
product2 = products.create_product("无线鼠标", 129.00, "电子产品")
print(f"商品1:{product1.display_info()}")
print(f"商品2:{product2.display_info()}")
# 方法3:从包中导入特定类/函数
from ecommerce.orders import Order
order = Order("ORD001", "张三", [product1, product2])
print(f"\n订单:{order.display_order()}")
# 方法4:使用子包
from ecommerce.database import DatabaseConnection
from ecommerce.utils import validate_email, format_price
db_conn = DatabaseConnection("localhost", 5432, "ecommerce_db")
print(f"\n数据库连接:{db_conn.connect()}")
email = "test@example.com"
print(f"\n邮箱验证:{email} -> {validate_email(email)}")
price = 1234.56
print(f"价格格式化:{price} -> {format_price(price)}")
# 方法5:相对导入(在包内部使用)
print("\n=== 包内部的相对导入 ===")
print("在包内部的模块中,可以使用相对导入来引用其他模块")
print("例如,在 orders.py 中导入 products:")
print(" from . import products # 导入同级模块")
print(" from .products import Product # 从同级模块导入")
print(" from ..utils import helpers # 从上级目录导入")
print(" from .database import models # 从子包导入")
2.4 __all__ 变量
python
print("\n=== __all__ 变量 ===")
# __all__ 变量定义了当使用 from module import * 时导入的内容
# 创建示例模块
module_content = '''
__all__ = ['public_func', 'PublicClass']
def public_func():
return "这是一个公共函数"
def _private_func():
return "这是一个私有函数"
class PublicClass:
def __init__(self):
self.name = "公共类"
class _PrivateClass:
def __init__(self):
self.name = "私有类"
public_var = "公共变量"
_private_var = "私有变量"
'''
with open("example_module.py", "w") as f:
f.write(module_content)
# 测试 __all__
from example_module import *
print("使用 from example_module import * 后:")
try:
print(f"public_func: {public_func()}")
except NameError as e:
print(f"错误:{e}")
try:
pc = PublicClass()
print(f"PublicClass: {pc.name}")
except NameError as e:
print(f"错误:{e}")
try:
print(f"_private_func: {_private_func()}")
except NameError as e:
print(f"_private_func 未导入")
try:
print(f"public_var: {public_var}")
except NameError as e:
print(f"public_var 未导入")
# 清理
import os
os.remove("example_module.py")
三、Python标准库模块
3.1 常用内置模块
python
print("\n=== Python常用内置模块 ===")
# 1. os - 操作系统接口
import os
print("1. os模块 - 操作系统接口")
print(f"当前工作目录: {os.getcwd()}")
print(f"目录列表: {os.listdir('.')[:5]}...")
print(f"路径存在: {os.path.exists('ecommerce')}")
print(f"路径是文件: {os.path.isfile('ecommerce/products.py')}")
print(f"路径是目录: {os.path.isdir('ecommerce')}\n")
# 2. sys - 系统相关参数和函数
import sys
print("2. sys模块 - 系统相关")
print(f"Python版本: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
print(f"平台: {sys.platform}")
print(f"默认编码: {sys.getdefaultencoding()}")
print(f"命令行参数: {sys.argv}\n")
# 3. datetime - 日期和时间处理
from datetime import datetime, date, time, timedelta
print("3. datetime模块 - 日期时间处理")
now = datetime.now()
print(f"当前时间: {now}")
print(f"格式化: {now.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"日期部分: {now.date()}")
print(f"时间部分: {now.time()}")
# 时间运算
tomorrow = now + timedelta(days=1)
print(f"明天: {tomorrow.strftime('%Y-%m-%d')}")
# 4. json - JSON数据处理
import json
print("\n4. json模块 - JSON数据处理")
# Python对象转JSON字符串
data = {
"name": "张三",
"age": 25,
"city": "北京",
"skills": ["Python", "JavaScript", "SQL"]
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(f"JSON字符串:\n{json_str}")
# JSON字符串转Python对象
parsed_data = json.loads(json_str)
print(f"解析后姓名: {parsed_data['name']}\n")
# 5. random - 生成随机数
import random
print("5. random模块 - 随机数生成")
print(f"随机整数(1-100): {random.randint(1, 100)}")
print(f"随机浮点数: {random.random()}")
print(f"随机选择: {random.choice(['苹果', '香蕉', '橙子'])}")
print(f"随机样本: {random.sample(range(100), 5)}\n")
# 6. re - 正则表达式
import re
print("6. re模块 - 正则表达式")
text = "我的邮箱是 zhangsan@example.com,电话是 138-1234-5678"
email_pattern = r'[\w.-]+@[\w.-]+.\w+'
phone_pattern = r'\d{3}-\d{4}-\d{4}'
emails = re.findall(email_pattern, text)
phones = re.findall(phone_pattern, text)
print(f"文本: {text}")
print(f"找到邮箱: {emails}")
print(f"找到电话: {phones}\n")
# 7. collections - 容器数据类型
from collections import Counter, defaultdict, namedtuple
print("7. collections模块 - 高级容器")
# Counter - 计数器
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
word_count = Counter(words)
print(f"单词计数: {word_count}")
print(f"最常见的2个: {word_count.most_common(2)}")
# defaultdict - 带默认值的字典
fruit_dict = defaultdict(list)
fruit_dict['red'].append('apple')
fruit_dict['yellow'].append('banana')
fruit_dict['red'].append('cherry')
print(f"默认字典: {dict(fruit_dict)}")
# namedtuple - 命名元组
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(f"命名元组: {p}, x={p.x}, y={p.y}\n")
# 8. itertools - 迭代器工具
import itertools
print("8. itertools模块 - 迭代器工具")
# 无限迭代器
counter = itertools.count(start=10, step=2)
print(f"无限计数前5个: {[next(counter) for _ in range(5)]}")
# 排列组合
letters = ['A', 'B', 'C']
print(f"排列(2个): {list(itertools.permutations(letters, 2))}")
print(f"组合(2个): {list(itertools.combinations(letters, 2))}")
3.2 第三方模块管理
python
print("\n=== 第三方模块管理 ===")
print("Python有丰富的第三方库,可以使用pip管理:")
print("\n常用pip命令:")
print(" 安装包: pip install package_name")
print(" 安装特定版本: pip install package_name==1.0.0")
print(" 升级包: pip install --upgrade package_name")
print(" 卸载包: pip uninstall package_name")
print(" 查看已安装包: pip list")
print(" 导出依赖: pip freeze > requirements.txt")
print(" 从文件安装: pip install -r requirements.txt")
print("\n常用第三方库示例:")
print(" 1. requests - HTTP请求库")
print(" 2. numpy - 科学计算")
print(" 3. pandas - 数据分析")
print(" 4. matplotlib - 数据可视化")
print(" 5. flask/django - Web框架")
print(" 6. beautifulsoup4 - HTML解析")
print(" 7. pillow - 图像处理")
print(" 8. openpyxl - Excel操作")
print("\n=== 虚拟环境 ===")
print("虚拟环境可以隔离不同项目的依赖:")
print("\n创建虚拟环境:")
print(" python -m venv myenv")
print("\n激活虚拟环境:")
print(" Windows: myenv\Scripts\activate")
print(" Mac/Linux: source myenv/bin/activate")
print("\n退出虚拟环境:")
print(" deactivate")
# 演示requests库的使用(如果已安装)
print("\n=== 使用第三方库:requests ===")
try:
import requests
# 发送GET请求
response = requests.get("https://api.github.com")
print(f"GitHub API状态码: {response.status_code}")
print(f"响应头: {dict(response.headers)[:3]}...")
# 发送带参数的GET请求
params = {"q": "python", "sort": "stars"}
response = requests.get("https://api.github.com/search/repositories", params=params)
print(f"搜索Python仓库,结果数: {response.json()['total_count']}")
except ImportError:
print("requests库未安装,运行 pip install requests 安装")
except Exception as e:
print(f"请求失败: {e}")
四、模块高级特性
4.1 模块缓存和重新加载
python
print("\n=== 模块缓存和重新加载 ===")
import importlib
# 创建测试模块
test_module_content = '''
message = "原始消息"
def get_message():
return message
'''
with open("test_module.py", "w") as f:
f.write(test_module_content)
# 第一次导入
import test_module
print(f"第一次导入: {test_module.get_message()}")
# 修改模块文件
test_module_content_updated = '''
message = "更新后的消息"
def get_message():
return f"更新: {message}"
'''
with open("test_module.py", "w") as f:
f.write(test_module_content_updated)
print(f"修改后直接调用: {test_module.get_message()} (仍然是旧版本)")
# 重新加载模块
importlib.reload(test_module)
print(f"重新加载后: {test_module.get_message()}")
# 清理
import os
os.remove("test_module.py")
print("\n=== 模块缓存位置 ===")
print("导入的模块缓存在 sys.modules 中:")
print(f"test_module 在缓存中: {'test_module' in sys.modules}")
print(f"缓存大小: {len(sys.modules)} 个模块")
# 查看模块缓存
print("\n前10个缓存的模块:")
for i, name in enumerate(list(sys.modules.keys())[:10], 1):
print(f" {i:2}. {name}")
4.2 动态模块创建
python
print("\n=== 动态创建模块 ===")
import types
# 创建一个模块对象
dynamic_module = types.ModuleType("dynamic_module")
# 添加内容到模块
dynamic_module.value = 42
dynamic_module.hello = lambda: "Hello from dynamic module!"
# 添加到sys.modules以便可以导入
sys.modules["dynamic_module"] = dynamic_module
# 现在可以像普通模块一样导入
import dynamic_module as dm
print(f"动态模块值: {dm.value}")
print(f"动态模块函数: {dm.hello()}")
print("\n=== 从字符串创建模块 ===")
# 从字符串创建模块
module_code = """
def greet(name):
return f"Hello, {name}!"
def calculate(a, b):
return a + b, a - b, a * b, a / b
CONSTANT = "这是一个常量"
"""
# 编译并执行模块代码
compiled_code = compile(module_code, "<string>", "exec")
string_module = types.ModuleType("string_module")
exec(compiled_code, string_module.__dict__)
# 使用模块
print(f"常量: {string_module.CONSTANT}")
print(f"问候: {string_module.greet('Python')}")
print(f"计算: {string_module.calculate(10, 2)}")
4.3 模块单例模式
python
print("\n=== 模块单例模式 ===")
# 在Python中,模块天然就是单例的
# 当模块第一次被导入时,它被初始化并缓存
# 后续导入都使用同一个实例
# singleton.py 内容
singleton_content = '''
class DatabaseConnection:
"""数据库连接单例"""
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection_count = 0
return cls._instance
def connect(self):
self.connection_count += 1
return f"连接 #{self.connection_count}"
def get_connection_count(self):
return self.connection_count
# 创建单例实例
db = DatabaseConnection()
'''
with open("singleton.py", "w") as f:
f.write(singleton_content)
# 在不同地方导入
import singleton as s1
import singleton as s2 # 实际上是同一个模块
print(f"s1.db is s2.db: {s1.db is s2.db}")
print(f"s1.db.connect(): {s1.db.connect()}")
print(f"s2.db.connect(): {s2.db.connect()}")
print(f"连接次数: {s1.db.get_connection_count()}")
# 清理
import os
os.remove("singleton.py")
五、实战项目:构建小型Web框架
python
print("\n=== 实战:构建小型Web框架 ===")
# 创建一个小型Web框架的结构
web_framework_structure = {
"web_framework/__init__.py": '''
"""
小型Web框架
"""
from .app import Application
from .request import Request
from .response import Response
from .router import Router
__version__ = "0.1.0"
__all__ = ['Application', 'Request', 'Response', 'Router']
''',
"web_framework/app.py": '''
"""
应用程序类
"""
from .router import Router
from .request import Request
from .response import Response
class Application:
"""Web应用"""
def __init__(self):
self.router = Router()
self.middleware = []
def route(self, path, methods=None):
"""路由装饰器"""
if methods is None:
methods = ['GET']
def decorator(handler):
for method in methods:
self.router.add_route(method, path, handler)
return handler
return decorator
def use(self, middleware):
"""添加中间件"""
self.middleware.append(middleware)
def handle_request(self, environ):
"""处理请求"""
# 创建请求对象
request = Request(environ)
# 执行中间件
for middleware in self.middleware:
middleware(request)
# 路由匹配
handler, params = self.router.match(request.method, request.path)
if handler:
# 执行处理器
response = handler(request, **params)
if isinstance(response, str):
response = Response(body=response)
return response
else:
# 404 未找到
return Response(status=404, body="404 Not Found")
def __call__(self, environ, start_response):
"""WSGI接口"""
response = self.handle_request(environ)
start_response(response.status, response.headers)
return [response.body.encode('utf-8')]
''',
"web_framework/request.py": '''
"""
请求类
"""
class Request:
"""HTTP请求"""
def __init__(self, environ):
self.environ = environ
self.method = environ.get('REQUEST_METHOD', 'GET')
self.path = environ.get('PATH_INFO', '/')
self.query_string = environ.get('QUERY_STRING', '')
self.headers = {}
# 解析头部
for key, value in environ.items():
if key.startswith('HTTP_'):
header_name = key[5:].replace('_', '-').title()
self.headers[header_name] = value
def get_header(self, name):
"""获取头部"""
return self.headers.get(name)
@property
def query_params(self):
"""查询参数"""
from urllib.parse import parse_qs
return parse_qs(self.query_string)
''',
"web_framework/response.py": '''
"""
响应类
"""
class Response:
"""HTTP响应"""
def __init__(self, status=200, body="", content_type="text/html; charset=utf-8"):
self.status = f"{status} OK" if status == 200 else f"{status}"
self.body = body
self.headers = [
('Content-Type', content_type),
('Content-Length', str(len(body.encode('utf-8'))))
]
def set_header(self, name, value):
"""设置头部"""
self.headers.append((name, value))
def json(self, data):
"""返回JSON响应"""
import json
self.body = json.dumps(data)
self.headers = [
('Content-Type', 'application/json'),
('Content-Length', str(len(self.body.encode('utf-8'))))
]
return self
''',
"web_framework/router.py": '''
"""
路由器类
"""
import re
class Route:
"""路由"""
def __init__(self, pattern, handler):
self.pattern = pattern
self.handler = handler
self.regex = self._compile_pattern(pattern)
def _compile_pattern(self, pattern):
"""编译路由模式为正则表达式"""
# 将 :param 转换为 (?P<param>[^/]+)
regex_pattern = re.sub(r':(\w+)', r'(?P<\1>[^/]+)', pattern)
return re.compile(f'^{regex_pattern}$')
def match(self, path):
"""匹配路径"""
match = self.regex.match(path)
if match:
return True, match.groupdict()
return False, {}
class Router:
"""路由器"""
def __init__(self):
self.routes = {} # method -> list of routes
def add_route(self, method, pattern, handler):
"""添加路由"""
if method not in self.routes:
self.routes[method] = []
route = Route(pattern, handler)
self.routes[method].append(route)
def match(self, method, path):
"""匹配路由"""
if method not in self.routes:
return None, {}
for route in self.routes[method]:
matched, params = route.match(path)
if matched:
return route.handler, params
return None, {}
'''
}
# 创建框架文件
print("创建Web框架结构...")
os.makedirs("web_framework", exist_ok=True)
for file_path, content in web_framework_structure.items():
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
print("框架创建完成!")
# 使用框架创建应用
print("\n=== 使用框架创建应用 ===")
app_content = '''
from web_framework import Application
from web_framework.response import Response
app = Application()
# 中间件
def logging_middleware(request):
print(f"[{request.method}] {request.path}")
app.use(logging_middleware)
# 路由
@app.route('/')
def home(request):
return """
<html>
<head><title>Home</title></head>
<body>
<h1>欢迎来到我的网站!</h1>
<p>这是一个使用自定义Web框架构建的网站。</p>
<ul>
<li><a href="/about">关于</a></li>
<li><a href="/hello/World">问候</a></li>
<li><a href="/api/info">API信息</a></li>
</ul>
</body>
</html>
"""
@app.route('/about')
def about(request):
return """
<html>
<head><title>About</title></head>
<body>
<h1>关于我们</h1>
<p>这是一个演示Web框架的小型网站。</p>
<a href="/">返回首页</a>
</body>
</html>
"""
@app.route('/hello/:name')
def hello(request, name):
return f"""
<html>
<head><title>Hello {name}</title></head>
<body>
<h1>Hello, {name}!</h1>
<p>欢迎来到我们的网站。</p>
<a href="/">返回首页</a>
</body>
</html>
"""
@app.route('/api/info')
def api_info(request):
response = Response()
return response.json({
'framework': 'Web Framework',
'version': '0.1.0',
'endpoints': ['/', '/about', '/hello/:name', '/api/info']
})
if __name__ == '__main__':
# 启动开发服务器
from wsgiref.simple_server import make_server
print("启动服务器:http://localhost:8000")
server = make_server('localhost', 8000, app)
server.serve_forever()
'''
with open("myapp.py", "w", encoding="utf-8") as f:
f.write(app_content)
print("应用创建完成:myapp.py")
print("运行 python myapp.py 启动服务器")
print("访问 http://localhost:8000 查看网站")
# 清理临时文件(在实际环境中保留)
import shutil
shutil.rmtree("web_framework", ignore_errors=True)
shutil.rmtree("ecommerce", ignore_errors=True)
os.remove("myapp.py")
六、总结:模块与包的核心要点
🎯 核心要点总结:
-
模块是
.py文件:包含Python代码,可以导入和使用pythonimport module from module import function -
包是包含
__init__.py的目录:组织相关模块pythonmypackage/ ├── __init__.py ├── module1.py └── module2.py -
导入方式:
- 绝对导入:
from package import module - 相对导入:
from . import module(在包内部使用)
- 绝对导入:
-
Python路径 :
sys.path定义了模块搜索路径
💡 最佳实践:
- 保持模块小巧:一个模块应该专注于一个功能
- 使用有意义的名称:模块名应该描述其功能
- 编写文档字符串:解释模块的用途
- 使用
__all__:控制from module import *的行为 - 组织包结构:相关功能放在同一个包中
🚀 高级特性:
- 动态导入 :
importlib.import_module() - 模块重载 :
importlib.reload() - 模块缓存 :
sys.modules - 单例模式:模块天然就是单例