← 返回主页

第15课: 最佳实践与项目实战

代码风格与规范

遵循PEP 8编码规范,编写清晰、可维护的代码。

PEP 8 核心规范

代码示例

# 好的代码风格
class UserManager:
    """用户管理类"""

    def __init__(self, database):
        self.database = database
        self.users = []

    def add_user(self, name, email):
        """添加新用户"""
        user = {
            'name': name,
            'email': email,
            'created_at': datetime.now()
        }
        self.users.append(user)
        return user

    def get_user_by_email(self, email):
        """根据邮箱查找用户"""
        for user in self.users:
            if user['email'] == email:
                return user
        return None


# 不好的代码风格
class usermanager:
    def __init__(self,db):
        self.db=db
        self.users=[]
    def addUser(self,n,e):
        u={'name':n,'email':e}
        self.users.append(u)
        return u

使用工具检查代码

# 安装代码检查工具
pip install pylint flake8 black

# 使用pylint检查代码
pylint myfile.py

# 使用flake8检查代码
flake8 myfile.py

# 使用black格式化代码
black myfile.py

# 使用isort整理导入
pip install isort
isort myfile.py

文档字符串

为函数、类和模块编写清晰的文档字符串。

def calculate_average(numbers):
    """
    计算数字列表的平均值。

    Args:
        numbers (list): 数字列表

    Returns:
        float: 平均值

    Raises:
        ValueError: 如果列表为空

    Examples:
        >>> calculate_average([1, 2, 3, 4, 5])
        3.0
    """
    if not numbers:
        raise ValueError("列表不能为空")
    return sum(numbers) / len(numbers)


class BankAccount:
    """
    银行账户类。

    Attributes:
        owner (str): 账户所有者
        balance (float): 账户余额
    """

    def __init__(self, owner, initial_balance=0):
        """
        初始化银行账户。

        Args:
            owner (str): 账户所有者姓名
            initial_balance (float, optional): 初始余额,默认为0
        """
        self.owner = owner
        self.balance = initial_balance

单元测试

编写测试确保代码质量和正确性。

使用unittest

import unittest

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

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


class TestMathFunctions(unittest.TestCase):

    def test_add(self):
        self.assertEqual(add(2, 3), 5)
        self.assertEqual(add(-1, 1), 0)

    def test_divide(self):
        self.assertEqual(divide(10, 2), 5)
        self.assertAlmostEqual(divide(10, 3), 3.333, places=3)

    def test_divide_by_zero(self):
        with self.assertRaises(ValueError):
            divide(10, 0)


if __name__ == '__main__':
    unittest.main()

使用pytest

# 安装pytest
pip install pytest

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

def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0

def test_add_strings():
    assert add("hello", "world") == "helloworld"

# 运行测试
pytest test_math.py

# 显示详细信息
pytest -v test_math.py

# 测试覆盖率
pip install pytest-cov
pytest --cov=mymodule tests/

日志记录

使用logging模块记录程序运行信息。

import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log'),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger(__name__)

# 使用日志
logger.debug("调试信息")
logger.info("程序启动")
logger.warning("警告信息")
logger.error("错误信息")
logger.critical("严重错误")

# 在函数中使用
def process_data(data):
    logger.info(f"开始处理数据,数据量: {len(data)}")
    try:
        result = perform_operation(data)
        logger.info("数据处理成功")
        return result
    except Exception as e:
        logger.error(f"数据处理失败: {e}", exc_info=True)
        raise

配置管理

使用配置文件管理应用设置。

使用JSON配置

# config.json
{
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "mydb"
    },
    "api": {
        "key": "your-api-key",
        "timeout": 30
    }
}

# 读取配置
import json

def load_config(config_file='config.json'):
    with open(config_file, 'r') as f:
        return json.load(f)

config = load_config()
db_host = config['database']['host']

使用环境变量

import os
from dotenv import load_dotenv

# 安装python-dotenv
# pip install python-dotenv

# .env文件
# DATABASE_URL=postgresql://localhost/mydb
# API_KEY=your-secret-key
# DEBUG=True

# 加载环境变量
load_dotenv()

DATABASE_URL = os.getenv('DATABASE_URL')
API_KEY = os.getenv('API_KEY')
DEBUG = os.getenv('DEBUG', 'False') == 'True'

项目结构

组织良好的项目结构提高代码可维护性。

myproject/
├── README.md              # 项目说明
├── requirements.txt       # 依赖列表
├── setup.py              # 安装配置
├── .env                  # 环境变量(不提交到git)
├── .gitignore            # Git忽略文件
├── config/               # 配置文件
│   ├── __init__.py
│   └── settings.py
├── src/                  # 源代码
│   ├── __init__.py
│   ├── main.py
│   ├── models/
│   │   ├── __init__.py
│   │   └── user.py
│   ├── services/
│   │   ├── __init__.py
│   │   └── user_service.py
│   └── utils/
│       ├── __init__.py
│       └── helpers.py
├── tests/                # 测试代码
│   ├── __init__.py
│   ├── test_models.py
│   └── test_services.py
└── docs/                 # 文档
    └── api.md

项目实战:任务管理系统

综合运用所学知识,构建一个完整的任务管理系统。

项目需求

核心代码实现

# task.py
from datetime import datetime
from enum import Enum

class TaskStatus(Enum):
    TODO = "待办"
    IN_PROGRESS = "进行中"
    DONE = "已完成"

class TaskPriority(Enum):
    LOW = "低"
    MEDIUM = "中"
    HIGH = "高"

class Task:
    def __init__(self, title, description="", priority=TaskPriority.MEDIUM):
        self.id = None
        self.title = title
        self.description = description
        self.priority = priority
        self.status = TaskStatus.TODO
        self.created_at = datetime.now()
        self.updated_at = datetime.now()

    def to_dict(self):
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'priority': self.priority.value,
            'status': self.status.value,
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat()
        }

    @classmethod
    def from_dict(cls, data):
        task = cls(data['title'], data['description'])
        task.id = data['id']
        task.priority = TaskPriority(data['priority'])
        task.status = TaskStatus(data['status'])
        task.created_at = datetime.fromisoformat(data['created_at'])
        task.updated_at = datetime.fromisoformat(data['updated_at'])
        return task


# task_manager.py
import json
from pathlib import Path

class TaskManager:
    def __init__(self, data_file='tasks.json'):
        self.data_file = Path(data_file)
        self.tasks = []
        self.next_id = 1
        self.load_tasks()

    def load_tasks(self):
        if self.data_file.exists():
            with open(self.data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.tasks = [Task.from_dict(t) for t in data]
                if self.tasks:
                    self.next_id = max(t.id for t in self.tasks) + 1

    def save_tasks(self):
        with open(self.data_file, 'w', encoding='utf-8') as f:
            data = [t.to_dict() for t in self.tasks]
            json.dump(data, f, ensure_ascii=False, indent=2)

    def add_task(self, title, description="", priority=TaskPriority.MEDIUM):
        task = Task(title, description, priority)
        task.id = self.next_id
        self.next_id += 1
        self.tasks.append(task)
        self.save_tasks()
        return task

    def get_task(self, task_id):
        for task in self.tasks:
            if task.id == task_id:
                return task
        return None

    def update_task(self, task_id, **kwargs):
        task = self.get_task(task_id)
        if task:
            for key, value in kwargs.items():
                if hasattr(task, key):
                    setattr(task, key, value)
            task.updated_at = datetime.now()
            self.save_tasks()
            return task
        return None

    def delete_task(self, task_id):
        task = self.get_task(task_id)
        if task:
            self.tasks.remove(task)
            self.save_tasks()
            return True
        return False

    def list_tasks(self, status=None):
        if status:
            return [t for t in self.tasks if t.status == status]
        return self.tasks


# main.py
def main():
    manager = TaskManager()

    while True:
        print("\n=== 任务管理系统 ===")
        print("1. 添加任务")
        print("2. 查看所有任务")
        print("3. 更新任务状态")
        print("4. 删除任务")
        print("5. 退出")

        choice = input("\n请选择操作: ")

        if choice == '1':
            title = input("任务标题: ")
            description = input("任务描述: ")
            task = manager.add_task(title, description)
            print(f"任务创建成功!ID: {task.id}")

        elif choice == '2':
            tasks = manager.list_tasks()
            if not tasks:
                print("暂无任务")
            else:
                for task in tasks:
                    print(f"[{task.id}] {task.title} - {task.status.value}")

        elif choice == '3':
            task_id = int(input("任务ID: "))
            print("1. 待办  2. 进行中  3. 已完成")
            status_choice = input("选择状态: ")
            status_map = {
                '1': TaskStatus.TODO,
                '2': TaskStatus.IN_PROGRESS,
                '3': TaskStatus.DONE
            }
            if status_choice in status_map:
                manager.update_task(task_id, status=status_map[status_choice])
                print("状态更新成功!")

        elif choice == '4':
            task_id = int(input("任务ID: "))
            if manager.delete_task(task_id):
                print("任务删除成功!")
            else:
                print("任务不存在")

        elif choice == '5':
            print("再见!")
            break

if __name__ == '__main__':
    main()

性能优化建议

安全最佳实践

持续学习资源

总结

恭喜你完成了Python学习之旅!你已经掌握了:

下一步建议: