Python模块与包:构建可维护的代码结构

在Python编程中,模块和包就像乐高积木的盒子------它们帮助你把相关的代码组织在一起,让大型项目变得井然有序。今天,我们来学习如何将Python代码组织成模块和包,构建可维护的代码结构!

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

想象一下,你正在开发一个电商网站:

  • 需要处理用户认证
  • 需要管理商品
  • 需要处理订单
  • 需要与数据库交互

如果不使用模块和包,你可能会有一个巨大的文件,里面包含所有功能,这样的代码:

  1. 难以阅读和维护
  2. 难以多人协作开发
  3. 难以重用特定功能

使用模块和包,你可以:

  • 将用户认证代码放在 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")

六、总结:模块与包的核心要点

🎯 核心要点总结:

  1. 模块是 .py 文件:包含Python代码,可以导入和使用

    python 复制代码
    import module
    from module import function
  2. 包是包含 __init__.py 的目录:组织相关模块

    python 复制代码
    mypackage/
    ├── __init__.py
    ├── module1.py
    └── module2.py
  3. 导入方式

    • 绝对导入:from package import module
    • 相对导入:from . import module(在包内部使用)
  4. Python路径sys.path 定义了模块搜索路径

💡 最佳实践:

  1. 保持模块小巧:一个模块应该专注于一个功能
  2. 使用有意义的名称:模块名应该描述其功能
  3. 编写文档字符串:解释模块的用途
  4. 使用 __all__ :控制 from module import * 的行为
  5. 组织包结构:相关功能放在同一个包中

🚀 高级特性:

  • 动态导入importlib.import_module()
  • 模块重载importlib.reload()
  • 模块缓存sys.modules
  • 单例模式:模块天然就是单例
相关推荐
BBB努力学习程序设计2 小时前
Python函数深度解析:从基础到高级装饰器
python·pycharm
抹除不掉的轻狂丶2 小时前
Java 日志框架完整指南:发展历史、核心组成与最佳实践
java·开发语言·python
目标是分享一切2 小时前
python卸载的时候出现0x80070643如何解决
python
Mqh1807622 小时前
day48 Tensorboard
python
tangjunjun-owen2 小时前
DINOv3 demo
python·深度学习·机器学习
IT北辰2 小时前
用 Python 自动解析药品规格并计算包装总容量 —— pandas + 正则实战
开发语言·python·pandas
python机器学习ML3 小时前
论文复现-以动物图像分类为例进行多模型性能对比分析
人工智能·python·神经网络·机器学习·计算机视觉·scikit-learn·sklearn
沃斯堡&蓝鸟3 小时前
DAY30 函数专题1:函数定义与参数
python
小oo呆3 小时前
【学习心得】Python的TypedDict(简介)
开发语言·python