Python入门:Python3基础练习题详解,从入门到熟练的 25 个实例(四)

在这里插入图片描述

在这里插入图片描述

Python入门:Python3基础练习题详解,从入门到熟练的 25 个实例(四)

Python入门:Python3基础练习题详解,从入门到熟练的 25 个实例(四),本文是关于Python3进阶练习题(76-100)的学习教程,涵盖面向对象编程、函数式编程、算法实现、文件操作、Web开发等领域。文中对每道题都提供了完整代码实现和详细解析,包括用魔术方法自定义对象打印、实现员工和学生管理系统、定义静态方法与类方法、构建图书馆管理系统,以及多继承、抽象类、生成器、迭代器、装饰器、上下文管理器、正则表达式验证、列表排序、数据处理、矩阵乘法、日期计算、排序与查找算法、CSV文件操作、元素筛选、迷宫求解、REST API实现、Flask应用创建和Web爬虫等内容,能帮助学习者巩固提升Python技能。

在这里插入图片描述

前言

    Python作为一门简洁、易读、功能强大的编程语言,其基础语法是入门学习的核心。掌握好基础语法,能为后续的编程实践打下坚实的基础。本文将全面讲解Python3的基础语法知识,适合编程初学者系统学习。Python以其简洁优雅的语法和强大的通用性,成为当今最受欢迎的编程语言。本专栏旨在系统性地带你从零基础入门到精通Python核心。无论你是零基础小白还是希望进阶的专业开发者,都将通过清晰的讲解、丰富的实例和实战项目,逐步掌握语法基础、核心数据结构、函数与模块、面向对象编程、文件处理、主流库应用(如数据分析、Web开发、自动化)以及面向对象高级特性,最终具备独立开发能力和解决复杂问题的思维,高效应对数据分析、人工智能、Web应用、自动化脚本等广泛领域的实际需求。

在这里插入图片描述


在这里插入图片描述

🥇 点击进入Python入门专栏,Python凭借简洁易读的语法,是零基础学习编程的理想选择。本专栏专为初学者设计,系统讲解Python核心基础:变量、数据类型、流程控制、函数、文件操作及常用库入门。通过清晰示例与实用小项目,助你快速掌握编程思维,打下坚实根基,迈出自动化办公、数据分析或Web开发的第一步。

🥇 点击进入Python小游戏实战专栏, 寓教于乐,用Python亲手打造经典小游戏!本专栏通过开发贪吃蛇、飞机大战、猜数字、简易版俄罗斯方块等趣味项目,在实践中掌握Python核心语法、面向对象编程、事件处理、图形界面(如Pygame)等关键技能,将枯燥的代码学习转化为可见的成果,让学习编程充满乐趣与成就感,快速提升实战能力。

🥇 点击进入Python小工具实战专栏,告别重复劳动,用Python打造效率神器!本专栏教你开发文件批量处理、自动邮件通知、简易爬虫、桌面提醒、密码生成器、天气查询等实用小工具。聚焦os、shutil、requests、smtplib、schedule等核心库,通过真实场景案例,快速掌握自动化脚本编写技巧,解放双手,显著提升工作与生活效率,让代码真正服务于你的日常。

🥇 点击进入Python爬虫实战专栏,解锁网络数据宝库!本专栏手把手教你使用Python核心库(如requests、BeautifulSoup、Scrapy)构建高效爬虫。从基础网页解析到动态页面抓取、数据存储(CSV/数据库)、反爬策略应对及IP代理使用,通过实战项目(如电商比价、新闻聚合、图片采集、舆情监控),掌握合法合规获取并利用网络数据的核心技能,让数据成为你的超能力。

🥇 点击进入Python项目实战专栏,告别碎片化学习,挑战真实项目!本专栏精选Web应用开发(Flask/Django)、数据分析可视化、自动化办公系统、简易爬虫框架、API接口开发等综合项目。通过需求分析、架构设计、编码实现、测试部署的全流程,深入掌握工程化开发、代码复用、调试排错与团队协作核心能力,积累高质量作品集,真正具备解决复杂问题的Python实战经验。


Python3基础练习题详解,从入门到熟练的 25 个实例(四)


🌐 前篇文章咱们练习了 Python3基础练习题详解,从入门到熟练的 25 个实例(三) ,如果忘记了,可以去重温一下,不停的重复敲击基础代码,有助于让你更加熟练掌握一门语言。今天咱们继续,八篇教程练习题实例 ,Python3基础练习题详解,从入门到熟练的 25 个实例(四),下面开始吧!

大家好!本文将针对 Python3 进阶练习题(76-100)进行详细讲解,包含完整代码实现和知识点解析。这些题目涵盖了面向对象编程、函数式编程、算法实现、文件操作等多个重要领域,非常适合有一定基础的 Python 学习者巩固提升。

76. 使用魔术方法__str__来自定义对象的打印输出

__str__ 是 Python 中的魔术方法,用于定义对象的字符串表示形式,当使用 print() 函数打印对象时会调用该方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    # 自定义对象的字符串表示
    def __str__(self):
        return f"Person(name: {self.name}, age: {self.age})"

# 测试
person = Person("张三", 25)
print(person)  # 输出:Person(name: 张三, age: 25)

控制台输出

在这里插入图片描述

解释

  • 未定义 __str__ 时,打印对象会显示类似 <__main__.Person object at 0x000001> 的内存地址
  • 定义后,print(person) 会调用 __str__ 方法,输出我们自定义的格式化字符串
  • 该方法必须返回一个字符串,否则会报错

77. 实现一个员工管理系统类

员工管理系统通常需要包含添加、删除、查询员工信息等功能。

class Employee:
    """员工类,存储员工基本信息"""
    def __init__(self, id, name, department, salary):
        self.id = id
        self.name = name
        self.department = department
        self.salary = salary

class EmployeeManagementSystem:
    """员工管理系统类"""
    def __init__(self):
        self.employees = []  # 存储员工对象的列表
    
    def add_employee(self, employee):
        """添加员工"""
        # 检查员工ID是否已存在
        for emp in self.employees:
            if emp.id == employee.id:
                print(f"错误:ID为{employee.id}的员工已存在")
                return
        self.employees.append(employee)
        print(f"员工{employee.name}添加成功")
    
    def remove_employee(self, emp_id):
        """根据ID删除员工"""
        for i, emp in enumerate(self.employees):
            if emp.id == emp_id:
                removed_emp = self.employees.pop(i)
                print(f"员工{removed_emp.name}已删除")
                return
        print(f"错误:未找到ID为{emp_id}的员工")
    
    def find_employee(self, emp_id):
        """根据ID查询员工"""
        for emp in self.employees:
            if emp.id == emp_id:
                return emp
        return None
    
    def display_all(self):
        """显示所有员工信息"""
        if not self.employees:
            print("没有员工信息")
            return
        print("所有员工信息:")
        for emp in self.employees:
            print(f"ID: {emp.id}, 姓名: {emp.name}, 部门: {emp.department}, 薪资: {emp.salary}")

# 测试
ems = EmployeeManagementSystem()
ems.add_employee(Employee(1, "张三", "技术部", 8000))
ems.add_employee(Employee(2, "李四", "市场部", 7000))
ems.display_all()
ems.remove_employee(1)
ems.display_all()

控制台输出

在这里插入图片描述

解释

  • 采用了类的封装思想,将员工信息和管理功能分离到两个类中
  • Employee 类负责存储数据,EmployeeManagementSystem 类负责业务逻辑
  • 实现了基本的 CRUD(增删改查)操作,实际应用中还可扩展排序、统计等功能

78. 使用类实现一个简单的学生成绩管理系统

学生成绩管理系统需要支持添加学生、录入成绩、查询成绩等功能。

class Student:
    """学生类,存储学生信息和成绩"""
    def __init__(self, student_id, name):
        self.student_id = student_id
        self.name = name
        self.grades = {}  # 用字典存储课程成绩,键为课程名,值为分数
    
    def add_grade(self, course, score):
        """添加课程成绩"""
        if 0 <= score <= 100:
            self.grades[course] = score
            return True
        print("成绩必须在0-100之间")
        return False
    
    def get_average(self):
        """计算平均成绩"""
        if not self.grades:
            return 0
        return sum(self.grades.values()) / len(self.grades)

class GradeManagementSystem:
    """成绩管理系统类"""
    def __init__(self):
        self.students = {}  # 用字典存储学生,键为学号
    
    def add_student(self, student):
        """添加学生"""
        if student.student_id in self.students:
            print(f"学号{student.student_id}已存在")
            return False
        self.students[student.student_id] = student
        print(f"学生{student.name}添加成功")
        return True
    
    def get_student(self, student_id):
        """获取学生信息"""
        return self.students.get(student_id)
    
    def display_student_grades(self, student_id):
        """显示学生所有成绩"""
        student = self.get_student(student_id)
        if not student:
            print("未找到该学生")
            return
        print(f"{student.name}的成绩:")
        for course, score in student.grades.items():
            print(f"{course}: {score}分")
        print(f"平均分:{student.get_average():.1f}分")

# 测试
gms = GradeManagementSystem()
gms.add_student(Student(1001, "张三"))
student = gms.get_student(1001)
if student:
    student.add_grade("数学", 90)
    student.add_grade("英语", 85)
gms.display_student_grades(1001)

控制台输出

在这里插入图片描述

解释

  • 学生的成绩用字典存储,方便按课程名查询
  • 实现了成绩有效性校验(0-100分)
  • 提供了平均分计算功能,体现了面向对象的封装性
  • 系统类使用学号作为键存储学生,提高查询效率

79. 使用 staticmethod 定义一个静态方法

静态方法是类中不需要访问实例变量或类变量的方法,使用 @staticmethod 装饰器定义。

class MathUtils:
    # 静态方法:计算圆的面积
    @staticmethod
    def circle_area(radius):
        """根据半径计算圆的面积"""
        if radius < 0:
            raise ValueError("半径不能为负数")
        return 3.14159 * radius ** 2
    
    # 静态方法:计算矩形的面积
    @staticmethod
    def rectangle_area(length, width):
        """计算矩形的面积"""
        if length < 0 or width < 0:
            raise ValueError("长和宽不能为负数")
        return length * width

# 调用静态方法:不需要创建类的实例,直接通过类名调用
print(f"半径为5的圆面积:{MathUtils.circle_area(5):.2f}")
print(f"长5宽3的矩形面积:{MathUtils.rectangle_area(5, 3)}")

控制台输出

在这里插入图片描述

解释

  • 静态方法不需要 selfcls 参数
  • 调用方式:类名.方法名(),无需创建实例
  • 适合定义工具类方法,即与类相关但不依赖类状态的功能
  • 与普通函数相比,静态方法的优势是可以组织在类的命名空间下,使代码结构更清晰

80. 使用 classmethod 定义一个类方法

类方法是绑定到类的方法,使用 @classmethod 装饰器定义,第一个参数是类本身(通常命名为 cls)。

class Person:
    species = "人类"  # 类变量
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    # 类方法:创建成年人类实例
    @classmethod
    def adult(cls, name):
        """创建一个成年人类实例(年龄默认18岁)"""
        return cls(name, 18)
    
    # 类方法:获取物种信息
    @classmethod
    def get_species(cls):
        """返回物种信息"""
        return cls.species
    
    def __str__(self):
        return f"{self.name}, {self.age}岁, {self.species}"

# 测试
# 创建普通实例
p1 = Person("张三", 20)
print(p1)

# 使用类方法创建实例
p2 = Person.adult("李四")
print(p2)

# 调用类方法获取类变量
print(f"物种:{Person.get_species()}")

解释

  • 类方法的第一个参数是类本身(cls),通过它可以访问类变量或调用其他类方法
  • 常用场景:
    • 定义备选构造函数(如示例中的 adult 方法)
    • 操作类变量
    • 实现与类相关的工具方法
  • 调用方式:类名.方法名()实例.方法名()

81. 使用 Python 实现一个图书馆管理系统

图书馆管理系统需要支持图书的入库、借阅、归还等功能。

class Book:
    """图书类"""
    def __init__(self, book_id, title, author, category):
        self.book_id = book_id
        self.title = title
        self.author = author
        self.category = category
        self.is_borrowed = False  # 是否被借出
    
    def __str__(self):
        status = "已借出" if self.is_borrowed else "可借阅"
        return f"ID: {self.book_id}, 书名: {self.title}, 作者: {self.author}, 类别: {self.category}, 状态: {status}"

class Library:
    """图书馆类"""
    def __init__(self):
        self.books = {}  # 存储图书,键为图书ID
        self.borrow_records = {}  # 借阅记录,键为图书ID,值为借阅人
    
    def add_book(self, book):
        """添加图书"""
        if book.book_id in self.books:
            print(f"图书ID {book.book_id} 已存在")
            return False
        self.books[book.book_id] = book
        print(f"图书《{book.title}》添加成功")
        return True
    
    def borrow_book(self, book_id, user):
        """借阅图书"""
        book = self.books.get(book_id)
        if not book:
            print("未找到该图书")
            return False
        if book.is_borrowed:
            print("该图书已被借出")
            return False
        book.is_borrowed = True
        self.borrow_records[book_id] = user
        print(f"用户{user}成功借阅《{book.title}》")
        return True
    
    def return_book(self, book_id):
        """归还图书"""
        book = self.books.get(book_id)
        if not book:
            print("未找到该图书")
            return False
        if not book.is_borrowed:
            print("该图书未被借出")
            return False
        book.is_borrowed = False
        user = self.borrow_records.pop(book_id)
        print(f"用户{user}成功归还《{book.title}》")
        return True
    
    def search_book(self, keyword):
        """根据关键词搜索图书"""
        results = []
        keyword = keyword.lower()
        for book in self.books.values():
            if (keyword in book.title.lower()) or (keyword in book.author.lower()) or (keyword in book.category.lower()):
                results.append(book)
        return results

# 测试
lib = Library()
lib.add_book(Book(1, "Python编程", "张三", "编程"))
lib.add_book(Book(2, "数据结构", "李四", "计算机"))

lib.borrow_book(1, "王五")
print(lib.search_book("python"))
lib.return_book(1)

解释

  • 系统包含 Book(图书)和 Library(图书馆)两个核心类
  • 实现了图书的添加、借阅、归还和搜索功能
  • 使用字典存储图书和借阅记录,提高查询效率
  • 搜索功能支持按书名、作者和类别进行模糊查询

82. 创建一个多继承的类

多继承指一个类同时继承多个父类,Python 支持多继承,继承顺序可通过 __mro__ 查看。

# 父类1:动物
class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        print(f"{self.name}在吃东西")

# 父类2:会跑的
class Runnable:
    def run(self):
        print(f"{self.name}在跑步")

# 父类3:会飞的
class Flyable:
    def fly(self):
        print(f"{self.name}在飞")

# 子类:鸟(继承Animal和Flyable)
class Bird(Animal, Flyable):
    def __init__(self, name):
        # 调用父类的构造方法
        super().__init__(name)
    
    def sing(self):
        print(f"{self.name}在唱歌")

# 子类:蝙蝠(继承Animal、Runnable和Flyable)
class Bat(Animal, Runnable, Flyable):
    def __init__(self, name):
        super().__init__(name)
    
    def sleep_by_day(self):
        print(f"{self.name}白天睡觉")

# 测试
bird = Bird("麻雀")
bird.eat()  # 继承自Animal
bird.fly()  # 继承自Flyable
bird.sing()  # 自身方法

bat = Bat("蝙蝠")
bat.eat()   # 继承自Animal
bat.run()   # 继承自Runnable
bat.fly()   # 继承自Flyable
bat.sleep_by_day()  # 自身方法

# 查看继承顺序
print("Bird类的继承顺序:", Bird.__mro__)

解释

  • 多继承的语法:class 子类名(父类1, 父类2, ...):
  • 使用 super() 调用父类的方法,Python 会按照 __mro__(方法解析顺序)查找父类
  • 多继承可能导致菱形问题(多个父类继承自同一个祖先类),使用时需谨慎设计类结构
  • 建议:多继承优先使用接口(无实现的抽象类),避免多个有实现的类带来的冲突

83. 使用抽象类定义接口

抽象类是包含抽象方法的类,不能实例化,只能被继承,子类必须实现所有抽象方法。Python 中使用 abc 模块实现抽象类。

from abc import ABC, abstractmethod

# 抽象类(接口):形状
class Shape(ABC):
    """形状接口,定义所有形状都必须实现的方法"""
    
    @abstractmethod
    def area(self):
        """计算面积(抽象方法,子类必须实现)"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """计算周长(抽象方法,子类必须实现)"""
        pass

# 实现类:圆形
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    # 实现抽象方法:计算面积
    def area(self):
        return 3.14159 * self.radius ** 2
    
    # 实现抽象方法:计算周长
    def perimeter(self):
        return 2 * 3.14159 * self.radius

# 实现类:矩形
class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width
    
    def area(self):
        return self.length * self.width
    
    def perimeter(self):
        return 2 * (self.length + self.width)

# 测试
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:
    print(f"面积:{shape.area():.2f}, 周长:{shape.perimeter():.2f}")

# 以下代码会报错(抽象类不能实例化)
# shape = Shape()  # TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter

解释

  • 定义抽象类需继承 ABC(Abstract Base Class)
  • 抽象方法用 @abstractmethod 装饰器标记,只有方法声明,没有实现
  • 子类必须实现所有抽象方法,否则也会被视为抽象类,不能实例化
  • 抽象类的作用:
    • 定义统一接口,强制子类遵循相同的方法规范
    • 实现多态,不同子类可以有不同实现,但对外提供一致的调用方式

84. 使用生成器实现一个无限序列

生成器(Generator)是一种特殊的迭代器,使用 yield 关键字返回值,可用于创建无限序列。

def infinite_sequence(start=0):
    """生成从start开始的无限整数序列"""
    current = start
    while True:
        yield current  # 使用yield返回当前值,并暂停函数执行
        current += 1

# 使用生成器
seq = infinite_sequence(5)

# 取前10个值
for _ in range(10):
    print(next(seq), end=" ")  # 输出:5 6 7 8 9 10 11 12 13 14

解释

  • 生成器函数通过 yield 关键字返回值,每次调用 next() 时从上次暂停的地方继续执行
  • 无限序列不会一次性生成所有值,而是按需生成,节省内存空间
  • 常见应用场景:
    • 生成无限数据流(如时间戳、计数器)
    • 处理大型数据集(无需一次性加载到内存)
  • 可通过 itertools 模块的 islice 工具截取生成器的部分内容:
    from itertools import islice
    # 直接获取第10到20个元素
    for num in islice(infinite_sequence(1), 10, 20):
        print(num, end=" ")  # 输出:11 12 13 14 15 16 17 18 19 20
    

85. 定义一个迭代器类

迭代器(Iterator)是实现了 __iter__()__next__() 方法的对象,可用于遍历数据集合。

class FibonacciIterator:
    """斐波那契数列迭代器"""
    def __init__(self, max_count=None):
        self.max_count = max_count  # 最大生成数量(None表示无限)
        self.count = 0  # 已生成数量
        self.a, self.b = 0, 1  # 斐波那契数列的前两个数
    
    def __iter__(self):
        """返回迭代器自身"""
        return self
    
    def __next__(self):
        """返回下一个值"""
        # 检查是否达到最大数量
        if self.max_count is not None and self.count >= self.max_count:
            raise StopIteration  # 触发迭代结束
        
        # 生成下一个斐波那契数
        current = self.a
        self.a, self.b = self.b, self.a + self.b
        self.count += 1
        return current

# 测试有限迭代
print("前10个斐波那契数:")
for num in FibonacciIterator(10):
    print(num, end=" ")  # 输出:0 1 1 2 3 5 8 13 21 34

# 测试无限迭代(需手动控制终止条件)
print("\n\n取无限序列的前5个:")
fib_infinite = FibonacciIterator()
for _ in range(5):
    print(next(fib_infinite), end=" ")  # 输出:0 1 1 2 3

解释

  • 迭代器协议:必须实现 __iter__()(返回自身)和 __next__()(返回下一个元素,无元素时抛出 StopIteration
  • 与生成器的区别:迭代器是类实现的,生成器是函数通过 yield 实现的,生成器本质是特殊的迭代器
  • 优势:
    • 支持惰性计算,无需提前生成所有元素
    • 适合遍历大型或无限数据集
  • 可通过 iter() 函数将可迭代对象(如列表、字符串)转换为迭代器

86. 实现一个装饰器函数

装饰器(Decorator)是用于修改函数或类行为的工具,本质是一个接受函数作为参数并返回新函数的高阶函数。

import time
from functools import wraps

def timer_decorator(func):
    """计算函数执行时间的装饰器"""
    # 保留原函数的元信息(如函数名、文档字符串)
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()  # 记录开始时间
        result = func(*args, **kwargs)  # 执行原函数
        end_time = time.time()  # 记录结束时间
        print(f"{func.__name__} 执行时间:{end_time - start_time:.6f}秒")
        return result  # 返回原函数的结果
    return wrapper

def log_decorator(func):
    """记录函数调用日志的装饰器"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"调用 {func.__name__},参数:{args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} 返回:{result}")
        return result
    return wrapper

# 使用装饰器(可叠加使用)
@log_decorator
@timer_decorator
def calculate_sum(n):
    """计算1到n的和"""
    return sum(range(1, n+1))

# 测试
calculate_sum(1000000)

输出示例

调用 calculate_sum,参数:(1000000,), {}
calculate_sum 执行时间:0.031250秒
calculate_sum 返回:500000500000

解释

  • 装饰器语法:@装饰器名 放在函数定义上方,等价于 函数名 = 装饰器名(函数名)
  • *args**kwargs 使装饰器可适配任意参数的函数
  • functools.wraps 用于保留原函数的元信息,避免装饰后函数名、文档字符串等被修改
  • 常见应用场景:
    • 性能测试(计时)
    • 日志记录
    • 权限验证
    • 缓存结果
  • 装饰器可叠加使用,执行顺序为从里到外(靠近函数的装饰器先执行)

87. 使用上下文管理器管理文件读取

上下文管理器(Context Manager)用于管理资源(如文件、网络连接),确保资源在使用后正确释放,通过 with 语句使用。

# 方式1:使用内置的文件上下文管理器
with open("example.txt", "w", encoding="utf-8") as f:
    f.write("Hello, 上下文管理器!")

# 方式2:自定义上下文管理器(实现__enter__和__exit__方法)
class FileManager:
    def __init__(self, filename, mode, encoding="utf-8"):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding
        self.file = None
    
    def __enter__(self):
        """进入上下文时执行,返回资源对象"""
        self.file = open(self.filename, self.mode, encoding=self.encoding)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文时执行,释放资源"""
        if self.file:
            self.file.close()
        # 处理异常(返回True表示已处理,不会向上传播)
        if exc_type:
            print(f"发生异常:{exc_val}")
        return False  # 不处理异常,向上传播

# 使用自定义上下文管理器读取文件
with FileManager("example.txt", "r") as f:
    content = f.read()
    print(content)  # 输出:Hello, 上下文管理器!

解释

  • 上下文管理器协议:实现 __enter__()(获取资源)和 __exit__()(释放资源)方法
  • with 语句的优势:
    • 自动释放资源,即使发生异常也能保证资源被正确关闭
    • 代码更简洁,避免手动调用 close() 方法
  • 常见内置上下文管理器:文件对象、threading.Locksqlite3.Connection
  • 也可通过 contextlib.contextmanager 装饰器用生成器实现上下文管理器:
    from contextlib import contextmanager
    
    @contextmanager
    def file_manager(filename, mode):
        f = open(filename, mode)
        try:
            yield f  # 相当于__enter__的返回值
        finally:
            f.close()  # 相当于__exit__的资源释放
    

88. 使用正则表达式实现邮箱验证

正则表达式(Regular Expression)是用于匹配字符串模式的工具,可高效验证、提取或替换文本。

import re

def is_valid_email(email):
    """验证邮箱格式是否合法"""
    # 邮箱正则表达式模式
    # 规则:
    # - 用户名:可包含字母、数字、下划线、点、加号、减号
    # - @符号:必须有且仅有一个
    # - 域名:包含字母、数字、点、减号,最后有一个点和至少2个字母的后缀
    pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
    
    # 使用re.match检查是否完全匹配
    return re.fullmatch(pattern, email) is not None

# 测试
test_emails = [
    "test@example.com",       # 合法
    "user.name+tag@example.co.uk",  # 合法
    "invalid-email.com",      # 不合法(缺少@)
    "user@.com",              # 不合法(域名开头为.)
    "user@com",               # 不合法(缺少域名后缀)
    "user@-example.com"       # 不合法(域名开头为-)
]

for email in test_emails:
    print(f"{email}: {'有效' if is_valid_email(email) else '无效'}")

输出

test@example.com: 有效
user.name+tag@example.co.uk: 有效
invalid-email.com: 无效
user@.com: 无效
user@com: 无效
user@-example.com: 无效

解释

  • 正则表达式常用符号:
    • ^:匹配字符串开头
    • $:匹配字符串结尾
    • []:字符集,匹配其中任意一个字符
    • +:匹配前面的元素1次或多次
    • *:匹配前面的元素0次或多次
    • ?:匹配前面的元素0次或1次
    • \.:匹配点号(. 本身是特殊字符,需转义)
  • re.fullmatch() 用于检查整个字符串是否完全匹配模式
  • 邮箱验证规则可根据实际需求调整,以上模式仅为通用规则,实际应用中可能需要更严格或宽松的匹配
  • 正则表达式调试工具:可使用 RegExr 等在线工具测试模式

89. 使用 lambda 表达式进行列表排序

lambda 表达式用于创建匿名函数,常与 sorted() 等函数结合使用,简化排序逻辑。

# 示例1:对字典列表按指定键排序
students = [
    {"name": "张三", "age": 20, "score": 85},
    {"name": "李四", "age": 19, "score": 92},
    {"name": "王五", "age": 21, "score": 78}
]

# 按年龄升序排序
sorted_by_age = sorted(students, key=lambda x: x["age"])
print("按年龄升序:", sorted_by_age)

# 按分数降序排序
sorted_by_score = sorted(students, key=lambda x: x["score"], reverse=True)
print("按分数降序:", sorted_by_score)

# 示例2:对元组列表按第二个元素排序
products = [("苹果", 5.99), ("香蕉", 3.99), ("橙子", 4.99)]

# 按价格升序排序
sorted_by_price = sorted(products, key=lambda x: x[1])
print("按价格升序:", sorted_by_price)

# 示例3:对字符串列表按长度排序
words = ["apple", "banana", "cherry", "date"]
sorted_by_length = sorted(words, key=lambda x: len(x))
print("按长度升序:", sorted_by_length)

输出

按年龄升序: [{'name': '李四', 'age': 19, 'score': 92}, {'name': '张三', 'age': 20, 'score': 85}, {'name': '王五', 'age': 21, 'score': 78}]
按分数降序: [{'name': '李四', 'age': 19, 'score': 92}, {'name': '张三', 'age': 20, 'score': 85}, {'name': '王五', 'age': 21, 'score': 78}]
按价格升序: [('香蕉', 3.99), ('橙子', 4.99), ('苹果', 5.99)]
按长度升序: ['date', 'apple', 'cherry', 'banana']

解释

  • lambda 表达式语法:lambda 参数: 表达式,返回一个函数对象
  • sorted() 函数的 key 参数接受一个函数,用于生成排序依据的值
  • reverse=True 表示降序排序(默认 reverse=False 为升序)
  • 优势:
    • 简化代码,无需单独定义排序函数
    • 适合简单的排序逻辑,复杂逻辑建议使用普通函数
  • 也可用于 list.sort() 方法(会修改原列表):
    students.sort(key=lambda x: x["name"])  # 按姓名排序
    

90. 使用 filtermap 函数处理数据

filter()map() 是函数式编程中的常用工具,filter() 用于筛选数据,map() 用于转换数据。

# 示例数据
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
people = [
    {"name": "张三", "age": 17},
    {"name": "李四", "age": 22},
    {"name": "王五", "age": 19},
    {"name": "赵六", "age": 15}
]

# 1. 使用filter()筛选数据
# filter(函数, 可迭代对象):返回符合条件(函数返回True)的元素
adults = list(filter(lambda x: x["age"] >= 18, people))
print("成年人:", adults)

even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print("偶数:", even_numbers)

# 2. 使用map()转换数据
# map(函数, 可迭代对象):对每个元素应用函数,返回转换后的结果
squares = list(map(lambda x: x **2, numbers))
print("平方数:", squares)

names = list(map(lambda x: x["name"], people))
print("姓名列表:", names)

# 3. 结合使用filter()和map()
# 筛选偶数并计算平方
even_squares = list(map(lambda x: x** 2, filter(lambda x: x % 2 == 0, numbers)))
print("偶数的平方:", even_squares)

输出

成年人: [{'name': '李四', 'age': 22}, {'name': '王五', 'age': 19}]
偶数: [2, 4, 6, 8, 10]
平方数: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
姓名列表: ['张三', '李四', '王五', '赵六']
偶数的平方: [4, 16, 36, 64, 100]

解释

  • filter() 工作原理:对可迭代对象中的每个元素应用函数,保留函数返回 True 的元素
  • map() 工作原理:对可迭代对象中的每个元素应用函数,返回所有函数调用结果组成的迭代器
  • 两者都返回迭代器,需通过 list() 转换为列表查看结果
  • 与列表推导式的对比:
    • 简单场景下,列表推导式更易读(如 [x for x in numbers if x % 2 == 0] 等价于 filter 示例)
    • filter()map() 更适合函数式编程风格,且可与其他函数式工具(如 reduce)结合使用
  • functools.reduce() 可用于对序列进行累积计算(如求和、求积)

91. 编写一个程序实现矩阵乘法

矩阵乘法是线性代数中的基本运算,两个矩阵 A(m×n)和 B(n×p)的乘积是一个 m×p 的矩阵 C,其中 C[i][j] = ΣA[i][k]×B[k][j](k从0到n-1)。

def matrix_multiply(a, b):
    """
    实现矩阵乘法
    :param a: 第一个矩阵(m×n)
    :param b: 第二个矩阵(n×p)
    :return: 乘积矩阵(m×p)
    """
    # 获取矩阵维度
    m = len(a)          # a的行数
    n = len(b)          # b的行数(需等于a的列数)
    p = len(b[0])       # b的列数
    
    # 检查矩阵维度是否兼容
    if len(a[0]) != n:
        raise ValueError("第一个矩阵的列数必须等于第二个矩阵的行数")
    
    # 初始化结果矩阵(m×p)
    result = [[0 for _ in range(p)] for _ in range(m)]
    
    # 矩阵乘法核心逻辑
    for i in range(m):          # 遍历a的行
        for j in range(p):      # 遍历b的列
            # 计算result[i][j]:a的第i行与b的第j列对应元素相乘后求和
            total = 0
            for k in range(n):  # 遍历a的列(或b的行)
                total += a[i][k] * b[k][j]
            result[i][j] = total
    
    return result

# 测试
a = [
    [1, 2, 3],
    [4, 5, 6]
]  # 2×3矩阵

b = [
    [7, 8],
    [9, 10],
    [11, 12]
]  # 3×2矩阵

c = matrix_multiply(a, b)
print("矩阵乘积:")
for row in c:
    print(row)  # 输出:[58, 64], [139, 154]

解释

  • 矩阵乘法的前提条件:第一个矩阵的列数必须等于第二个矩阵的行数
  • 结果矩阵的行数等于第一个矩阵的行数,列数等于第二个矩阵的列数
  • 核心公式:result[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] + ... + a[i][n-1]*b[n-1][j]
  • 优化方向:
    • 对于大型矩阵,可使用 numpy 库的 dot() 方法(基于C实现,效率更高)
    • 示例:import numpy; print(numpy.dot(a, b))

92. 使用 Python 计算两个日期之间的天数差

Python 的 datetime 模块提供了日期时间处理功能,可方便计算两个日期的差值。

from datetime import date, datetime

def days_between_dates(date1, date2):
    """
    计算两个日期之间的天数差(绝对值)
    :param date1: 第一个日期(date或datetime对象)
    :param date2: 第二个日期(date或datetime对象)
    :return: 天数差
    """
    delta = date1 - date2
    return abs(delta.days)

# 方法1:使用date对象(仅日期)
d1 = date(2023, 1, 1)
d2 = date(2023, 12, 31)
print(f"2023年1月1日到2023年12月31日相差:{days_between_dates(d1, d2)}天")

# 方法2:使用datetime对象(包含时间,时间部分不影响天数差)
dt1 = datetime(2023, 2, 1)
dt2 = datetime(2023, 3, 1)
print(f"2023年2月1日到2023年3月1日相差:{days_between_dates(dt1, dt2)}天")

# 方法3:从字符串解析日期
date_str1 = "2024-02-28"
date_str2 = "2024-03-01"  # 2024是闰年,2月有29天
dt1 = datetime.strptime(date_str1, "%Y-%m-%d").date()
dt2 = datetime.strptime(date_str2, "%Y-%m-%d").date()
print(f"{date_str1}{date_str2}相差:{days_between_dates(dt1, dt2)}天")

输出

2023年1月1日到2023年12月31日相差:364天
2023年2月1日到2023年3月1日相差:28天
2024-02-28到2024-03-01相差:2天

解释

  • date 类用于处理日期(年、月、日),datetime 类用于处理日期和时间
  • 两个日期对象相减得到 timedelta 对象,其 days 属性即为天数差
  • strptime() 用于将字符串解析为日期对象,格式符说明:
    • %Y:四位数年份(如2023)
    • %m:两位数月份(01-12)
    • %d:两位数日期(01-31)
  • 常见需求扩展:
    • 计算n天后的日期:new_date = d1 + timedelta(days=n)
    • 格式化日期为字符串:d1.strftime("%Y年%m月%d日")

93. 使用 Python 实现冒泡排序算法

冒泡排序是一种简单的排序算法,通过重复比较相邻元素并交换位置,使较大的元素"浮"到末尾。

def bubble_sort(arr):
    """
    冒泡排序算法
    :param arr: 待排序的列表
    :return: 排序后的列表(从小到大)
    """
    # 复制原列表,避免修改输入数据
    arr = arr.copy()
    n = len(arr)
    
    # 外层循环:控制需要进行多少轮比较
    for i in range(n - 1):
        # 标记本轮是否发生交换,优化算法
        swapped = False
        
        # 内层循环:每轮比较相邻元素
        # 每轮结束后,最大的元素已"浮"到末尾,无需再比较
        for j in range(n - 1 - i):
            if arr[j] > arr[j + 1]:
                # 交换相邻元素
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        
        # 如果本轮没有交换,说明列表已有序,提前退出
        if not swapped:
            break
    
    return arr

# 测试
test_arrays = [
    [3, 1, 4, 1, 5, 9, 2, 6],
    [5, 4, 3, 2, 1],
    [1, 2, 3, 4, 5]  # 已排序,测试优化效果
]

for arr in test_arrays:
    sorted_arr = bubble_sort(arr)
    print(f"原始列表:{arr},排序后:{sorted_arr}")

输出

原始列表:[3, 1, 4, 1, 5, 9, 2, 6],排序后:[1, 1, 2, 3, 4, 5, 6, 9]
原始列表:[5, 4, 3, 2, 1],排序后:[1, 2, 3, 4, 5]
原始列表:[1, 2, 3, 4, 5],排序后:[1, 2, 3, 4, 5]

解释

  • 算法特点:
    • 时间复杂度:平均和最坏情况为 O(n²),最好情况(已排序)为 O(n)
    • 空间复杂度:O(1)(原地排序)
    • 稳定性:稳定排序(相等元素的相对位置不变)
  • 优化点:
    • 加入 swapped 标记,当一轮比较中没有交换时,说明列表已有序,可提前终止
    • 每轮循环的范围逐渐缩小(n-1-i),因为尾部的元素已排好序
  • 适用场景:小规模数据集或接近有序的数据集

94. 编写一个程序实现二分查找

二分查找(Binary Search)是一种高效的查找算法,适用于已排序的数据集,通过不断缩小查找范围来定位目标值。

def binary_search(arr, target):
    """
    二分查找算法(迭代实现)
    :param arr: 已排序的列表(从小到大)
    :param target: 目标值
    :return: 目标值在列表中的索引,未找到返回-1
    """
    left = 0               # 左边界索引
    right = len(arr) - 1   # 右边界索引
    
    while left <= right:
        mid = (left + right) // 2  # 计算中间索引
        mid_val = arr[mid]
        
        if mid_val == target:
            return mid  # 找到目标,返回索引
        elif mid_val < target:
            left = mid + 1  # 目标在右半部分,调整左边界
        else:
            right = mid - 1  # 目标在左半部分,调整右边界
    
    return -1  # 未找到目标

# 递归实现(可选)
def binary_search_recursive(arr, target, left, right):
    if left > right:
        return -1
    mid = (left + right) // 2
    if arr[mid] == target:
        return mid
    elif arr[mid] < target:
        return binary_search_recursive(arr, target, mid + 1, right)
    else:
        return binary_search_recursive(arr, target, left, mid - 1)

# 测试
sorted_arr = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
targets = [23, 5, 100, 8]

for target in targets:
    index = binary_search(sorted_arr, target)
    if index != -1:
        print(f"找到 {target},索引为 {index}")
    else:
        print(f"未找到 {target}")

# 测试递归版本
print("\n递归版本测试:")
print(binary_search_recursive(sorted_arr, 16, 0, len(sorted_arr)-1))  # 输出:4

输出

找到 23,索引为 5
找到 5,索引为 1
未找到 100
找到 8,索引为 2

递归版本测试:
4

解释

  • 算法步骤:
    1. 确定查找范围的左右边界(leftright
    2. 计算中间索引 mid,比较中间值与目标值
    3. 根据比较结果调整边界(左半部分或右半部分)
    4. 重复步骤2-3,直到找到目标或范围为空
  • 算法特点:
    • 时间复杂度:O(log n)(远优于线性查找的 O(n))
    • 空间复杂度:迭代实现 O(1),递归实现 O(log n)(递归栈开销)
    • 前提:数据集必须已排序
  • 适用场景:静态数据(不常修改)的查找,如字典查询、数据库索引等

95. 使用 Python 读取并写入 CSV 文件

CSV(逗号分隔值)是一种常见的表格数据格式,Python 的 csv 模块提供了专门的处理工具。

import csv

# 1. 写入CSV文件
data = [
    ["姓名", "年龄", "城市"],
    ["张三", 25, "北京"],
    ["李四", 30, "上海"],
    ["王五", 28, "广州"]
]

with open("people.csv", "w", encoding="utf-8", newline="") as f:
    # 创建CSV写入器
    writer = csv.writer(f)
    # 写入多行数据
    writer.writerows(data)
    # 也可单行写入:writer.writerow(["赵六", 35, "深圳"])

# 2. 读取CSV文件
print("读取CSV文件内容:")
with open("people.csv", "r", encoding="utf-8") as f:
    # 创建CSV阅读器
    reader = csv.reader(f)
    # 遍历所有行
    for row in reader:
        print(row)

# 3. 读写字典格式的CSV(带表头)
fieldnames = ["姓名", "年龄", "城市"]
dict_data = [
    {"姓名": "孙七", "年龄": 40, "城市": "杭州"},
    {"姓名": "周八", "年龄": 33, "城市": "成都"}
]

# 写入字典数据
with open("people_dict.csv", "w", encoding="utf-8", newline="") as f:
    # 创建字典写入器(指定表头)
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()  # 写入表头
    writer.writerows(dict_data)  # 写入数据行

# 读取字典数据
print("\n读取字典格式CSV:")
with open("people_dict.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)  # 自动使用第一行作为表头
    for row in reader:
        print(f"{row['姓名']}{row['年龄']}岁,来自{row['城市']}")

解释

  • newline="" 用于避免写入时出现空行(Windows系统特有的问题)
  • csv.writer 适用于列表形式的数据,csv.DictWriter 适用于字典形式的数据(需指定表头)
  • 读取时,csv.reader 返回列表,csv.DictReader 返回字典(键为表头)
  • 高级用法:
    • 自定义分隔符:csv.reader(f, delimiter=";")(如处理分号分隔的文件)
    • 处理带引号的字段:默认支持带引号的字段(如包含逗号的内容)
    • 对于大型CSV文件,可使用 pandas 库(pd.read_csv()pd.to_csv())更高效处理

96. 实现一个函数找出列表中所有符合条件的元素

通过自定义条件函数,可灵活筛选列表中符合要求的元素。

def find_elements(lst, condition):
    """
    找出列表中所有符合条件的元素
    :param lst: 待筛选的列表
    :param condition: 条件函数(返回布尔值)
    :return: 符合条件的元素组成的新列表
    """
    return [item for item in lst if condition(item)]

# 示例1:筛选偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = find_elements(numbers, lambda x: x % 2 == 0)
print("偶数:", even_numbers)

# 示例2:筛选长度大于3的字符串
words = ["apple", "cat", "banana", "dog", "cherry"]
long_words = find_elements(words, lambda x: len(x) > 3)
print("长度大于3的单词:", long_words)

# 示例3:筛选年龄大于等于18的成年人
people = [
    {"name": "张三", "age": 17},
    {"name": "李四", "age": 22},
    {"name": "王五", "age": 19}
]
adults = find_elements(people, lambda x: x["age"] >= 18)
print("成年人:", adults)

# 示例4:使用自定义函数作为条件
def is_prime(n):
    """判断是否为质数"""
    if n <= 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

primes = find_elements(range(1, 30), is_prime)
print("1-30中的质数:", primes)

输出

偶数: [2, 4, 6, 8, 10]
长度大于3的单词: ['apple', 'banana', 'cherry']
成年人: [{'name': '李四', 'age': 22}, {'name': '王五', 'age': 19}]
1-30中的质数: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

解释

  • 核心思想:通过回调函数condition 参数)定义筛选规则,使函数具有通用性
  • 实现方式:使用列表推导式遍历元素,仅保留 condition(item)True 的元素
  • 优势:
    • 代码复用:一个函数可以应对各种筛选需求,无需为每种条件单独编写函数
    • 灵活性高:条件函数可以是简单的 lambda 表达式,也可以是复杂的自定义函数
  • filter() 函数的对比:
    • 功能相似,但 find_elements 直接返回列表,而 filter() 返回迭代器
    • 列表推导式的可读性通常优于 filter()lambda 的组合
  • 扩展场景:
    • 可添加 reverse 参数控制结果顺序
    • 可添加 limit 参数限制返回元素数量

97. 实现一个迷宫求解算法

迷宫求解是经典的路径搜索问题,常用深度优先搜索(DFS)或广度优先搜索(BFS)算法。以下实现基于DFS。

def solve_maze(maze, start, end):
    """
    深度优先搜索求解迷宫
    :param maze: 迷宫矩阵(0表示通路,1表示墙壁)
    :param start: 起点坐标 (row, col)
    :param end: 终点坐标 (row, col)
    :return: 从起点到终点的路径列表,无解则返回空列表
    """
    # 获取迷宫尺寸
    rows = len(maze)
    cols = len(maze[0]) if rows > 0 else 0
    
    # 记录已访问的位置
    visited = [[False for _ in range(cols)] for _ in range(rows)]
    
    # 可能的移动方向:上、右、下、左
    directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
    
    # 深度优先搜索递归函数
    def dfs(current, path):
        # 到达终点,返回路径
        if current == end:
            return path + [current]
        
        row, col = current
        
        # 检查当前位置是否合法(在迷宫内、不是墙壁、未访问)
        if (0 <= row < rows and 0 <= col < cols and
            maze[row][col] == 0 and not visited[row][col]):
            
            visited[row][col] = True  # 标记为已访问
            
            # 尝试所有方向
            for dr, dc in directions:
                next_row, next_col = row + dr, col + dc
                result = dfs((next_row, next_col), path + [current])
                if result:  # 找到路径则返回
                    return result
            
            # 回溯:如果所有方向都走不通,取消标记
            visited[row][col] = False
        
        return None  # 无有效路径
    
    # 开始搜索
    return dfs(start, [])

# 测试迷宫
maze = [
    [0, 1, 0, 0, 0],
    [0, 1, 0, 1, 0],
    [0, 0, 0, 1, 0],
    [0, 1, 1, 1, 0],
    [0, 0, 0, 0, 0]
]
start = (0, 0)  # 起点:左上角
end = (4, 4)    # 终点:右下角

path = solve_maze(maze, start, end)

if path:
    print("找到路径:")
    for step in path:
        print(step, end=" -> ")
    print("终点")
else:
    print("未找到路径")

输出

找到路径:
(0, 0) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2) -> (3, 2) -> (4, 2) -> (4, 3) -> (4, 4) -> 终点

解释

  • 迷宫表示:二维列表,0 表示可通行,1 表示障碍物
  • DFS 算法核心:
    1. 从起点开始,尝试所有可能的移动方向
    2. 标记已访问的位置,避免重复探索
    3. 若到达终点则返回路径,否则回溯到上一步继续尝试其他方向
  • 关键数据结构:
    • visited 矩阵:记录已访问的位置,防止死循环
    • directions 列表:定义上下左右四个移动方向
  • 优化方向:
    • BFS 算法可找到最短路径(DFS 不一定是最短路径)
    • 可添加路径标记功能,在迷宫矩阵中标记出求解路径

98. 使用 Python 模块实现 REST API

使用 Flask 框架可快速实现 REST API,以下示例创建一个简单的图书管理 API。

首先安装 Flask:pip install flask

from flask import Flask, jsonify, request

app = Flask(__name__)

# 模拟数据库
books = [
    {"id": 1, "title": "Python编程", "author": "张三"},
    {"id": 2, "title": "数据结构", "author": "李四"}
]
next_id = 3  # 下一个可用ID

# 获取所有图书
@app.route('/api/books', methods=['GET'])
def get_books():
    return jsonify({"books": books})

# 获取单本图书
@app.route('/api/books/<int:book_id>', methods=['GET'])
def get_book(book_id):
    book = next((b for b in books if b['id'] == book_id), None)
    if book:
        return jsonify(book)
    return jsonify({"error": "图书不存在"}), 404

# 添加图书
@app.route('/api/books', methods=['POST'])
def add_book():
    global next_id
    if not request.json or 'title' not in request.json:
        return jsonify({"error": "标题不能为空"}), 400
    
    book = {
        "id": next_id,
        "title": request.json['title'],
        "author": request.json.get('author', "")
    }
    books.append(book)
    next_id += 1
    return jsonify(book), 201  # 201表示创建成功

# 更新图书
@app.route('/api/books/<int:book_id>', methods=['PUT'])
def update_book(book_id):
    book = next((b for b in books if b['id'] == book_id), None)
    if not book:
        return jsonify({"error": "图书不存在"}), 404
    if not request.json:
        return jsonify({"error": "无效数据"}), 400
    
    book['title'] = request.json.get('title', book['title'])
    book['author'] = request.json.get('author', book['author'])
    return jsonify(book)

# 删除图书
@app.route('/api/books/<int:book_id>', methods=['DELETE'])
def delete_book(book_id):
    global books
    book = next((b for b in books if b['id'] == book_id), None)
    if not book:
        return jsonify({"error": "图书不存在"}), 404
    
    books = [b for b in books if b['id'] != book_id]
    return jsonify({"result": "删除成功"}), 200

if __name__ == '__main__':
    app.run(debug=True)  # 启动服务器,debug模式便于开发

使用方法

  • 启动服务器后,可通过工具(如 Postman、curl)测试 API:
    • 获取所有图书:GET http://localhost:5000/api/books
    • 添加图书:POST http://localhost:5000/api/books,请求体为 {"title": "新图书", "author": "作者"}
    • 更新图书:PUT http://localhost:5000/api/books/1
    • 删除图书:DELETE http://localhost:5000/api/books/1

解释

  • REST API 设计原则:使用 HTTP 方法(GET/POST/PUT/DELETE)对应 CRUD 操作
  • jsonify() 用于将 Python 字典转换为 JSON 响应
  • request.json 用于获取请求体中的 JSON 数据
  • 状态码说明:
    • 200:成功
    • 201:创建成功
    • 400:请求错误
    • 404:资源不存在
  • 生产环境优化:
    • 使用数据库(如 SQLAlchemy 连接 MySQL)替代模拟数据
    • 添加身份验证(如 JWT)
    • 处理异常和输入验证

99. 创建一个 Flask 或 Django 应用

以下创建一个简单的 Flask 应用,实现用户注册和登录功能(基于会话的认证)。

from flask import Flask, render_template_string, request, redirect, url_for, session
import hashlib

app = Flask(__name__)
app.secret_key = 'supersecretkey'  # 用于会话加密,生产环境需更换为随机字符串

# 模拟用户数据库(实际应用使用数据库)
users = {
    # 密码使用MD5哈希存储(实际应用建议使用更安全的算法如bcrypt)
    "admin": hashlib.md5("admin123".encode()).hexdigest()
}

# HTML模板(实际应用使用单独的templates文件夹)
REGISTER_TEMPLATE = """
<h1>注册</h1>
<form method="post">
    用户名: <input type="text" name="username" required><br>
    密码: <input type="password" name="password" required><br>
    <button type="submit">注册</button>
</form>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<p>已有账号?<a href="{{ url_for('login') }}">登录</a></p>
"""

LOGIN_TEMPLATE = """
<h1>登录</h1>
<form method="post">
    用户名: <input type="text" name="username" required><br>
    密码: <input type="password" name="password" required><br>
    <button type="submit">登录</button>
</form>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<p>没有账号?<a href="{{ url_for('register') }}">注册</a></p>
"""

HOME_TEMPLATE = """
<h1>欢迎回来,{{ username }}!</h1>
<a href="{{ url_for('logout') }}">退出登录</a>
"""

# 路由
@app.route('/')
def home():
    # 检查用户是否登录
    if 'username' in session:
        return render_template_string(HOME_TEMPLATE, username=session['username'])
    return redirect(url_for('login'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        if username in users:
            return render_template_string(REGISTER_TEMPLATE, error="用户名已存在")
        
        # 存储密码哈希
        users[username] = hashlib.md5(password.encode()).hexdigest()
        return redirect(url_for('login'))
    
    return render_template_string(REGISTER_TEMPLATE)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        password_hash = hashlib.md5(password.encode()).hexdigest()
        
        if username in users and users[username] == password_hash:
            # 登录成功,设置会话
            session['username'] = username
            return redirect(url_for('home'))
        else:
            return render_template_string(LOGIN_TEMPLATE, error="用户名或密码错误")
    
    return render_template_string(LOGIN_TEMPLATE)

@app.route('/logout')
def logout():
    # 清除会话
    session.pop('username', None)
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(debug=True)

功能说明

  • 访问 http://localhost:5000 会自动跳转至登录页
  • 支持用户注册(用户名和密码)
  • 登录后保存会话状态,可访问主页
  • 提供退出登录功能

解释

  • 会话管理:session 对象用于存储用户状态,依赖 secret_key 加密
  • 密码安全:示例使用 MD5 哈希存储密码(仅演示用),实际应用应使用 bcrypt 等带盐值的哈希算法
  • 模板系统:示例使用内联模板,实际项目建议将模板文件放在 templates 文件夹中
  • 扩展功能:
    • 添加邮箱验证
    • 实现密码重置
    • 连接数据库(如 SQLite、MySQL)

100. 使用 Python 实现一个简单的 web 爬虫

使用 requestsBeautifulSoup 库爬取网页内容,以下示例爬取豆瓣电影 Top250 的电影名称和评分。

首先安装依赖:pip install requests beautifulsoup4

import requests
from bs4 import BeautifulSoup
import time

def crawl_douban_top250(page=0):
    """
    爬取豆瓣电影Top250
    :param page: 页码(0开始,每页25部电影)
    :return: 电影列表,每个元素为字典{"title": 标题, "rating": 评分}
    """
    url = f"https://movie.douban.com/top250?start={page*25}&filter="
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    
    try:
        # 发送请求
        response = requests.get(url, headers=headers)
        response.raise_for_status()  # 抛出HTTP错误状态码
        
        # 解析HTML
        soup = BeautifulSoup(response.text, 'html.parser')
        items = soup.find_all('div', class_='item')
        
        movies = []
        for item in items:
            # 提取电影标题
            title = item.find('span', class_='title').text
            
            # 提取评分
            rating = item.find('span', class_='rating_num').text
            
            movies.append({
                "title": title,
                "rating": rating
            })
        
        return movies
    
    except requests.exceptions.RequestException as e:
        print(f"爬取失败:{e}")
        return []

# 爬取前100部电影(4页)
all_movies = []
for page in range(4):
    print(f"爬取第{page+1}页...")
    movies = crawl_douban_top250(page)
    all_movies.extend(movies)
    time.sleep(1)  # 休眠1秒,避免请求过于频繁

# 保存结果
with open("douban_top250.txt", "w", encoding="utf-8") as f:
    for i, movie in enumerate(all_movies, 1):
        f.write(f"{i}. {movie['title']} 评分:{movie['rating']}\n")

print("爬取完成,结果已保存到 douban_top250.txt")

解释

  • 核心库作用:
    • requests:发送 HTTP 请求,获取网页内容
    • BeautifulSoup:解析 HTML 文档,提取所需数据
  • 反爬措施:
    • 设置 User-Agent 头,模拟浏览器请求
    • 加入延迟(time.sleep),避免短时间内发送大量请求
  • 数据提取:
    • 使用 find()find_all() 查找 HTML 元素
    • 通过 class_ 参数匹配特定类名的元素
  • 注意事项:
    • 遵守网站的 robots.txt 协议
    • 不要过度爬取,以免给服务器造成负担
    • 部分网站需要登录或处理验证码,需额外处理

扩展功能

  • 爬取更多字段(导演、主演、上映年份等)
  • 实现分页爬取全部250部电影
  • 将结果保存为 CSV 或 JSON 格式

总结

本文涵盖了 Python3 进阶练习题 76-100 的实现,涉及面向对象编程、函数式编程、算法、文件操作、Web 开发等多个领域。这些题目不仅能帮助巩固基础知识,还能培养解决实际问题的能力。

建议学习时结合实际场景练习,例如:

  • 将学生管理系统与文件存储结合,实现数据持久化
  • 使用爬虫收集数据后,用数据分析库(如 pandas)进行处理
  • 尝试优化算法,比较不同实现的效率差异

希望本文对大家的 Python 学习有所帮助,祝大家编程愉快!

💡下一篇咱们学习 Python3基础练习题详解,从入门到熟练的 25 个实例(五)!

附录:扩展学习资源

  1. 官方资源
  2. 本专栏特色资源
    • 代码资源仓库:CSDN专属资源在线获取
    • 海量Python教程:关注公众号:xcLeigh,获取网盘地址
    • 一对一答疑:添加微信与博主在线沟通(备注“Python专栏”

联系博主

    xcLeigh 博主全栈领域优质创作者,博客专家,目前,活跃在CSDN、微信公众号、小红书、知乎、掘金、快手、思否、微博、51CTO、B站、腾讯云开发者社区、阿里云开发者社区等平台,全网拥有几十万的粉丝,全网统一IP为 xcLeigh。希望通过我的分享,让大家能在喜悦的情况下收获到有用的知识。主要分享编程、开发工具、算法、技术学习心得等内容。很多读者评价他的文章简洁易懂,尤其对于一些复杂的技术话题,他能通过通俗的语言来解释,帮助初学者更好地理解。博客通常也会涉及一些实践经验,项目分享以及解决实际开发中遇到的问题。如果你是开发领域的初学者,或者在学习一些新的编程语言或框架,关注他的文章对你有很大帮助。

    亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。

     愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。

    至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。


     💞 关注博主 🌀 带你实现畅游前后端!

     🏰 大屏可视化 🌀 带你体验酷炫大屏!

     💯 神秘个人简介 🌀 带你体验不一样得介绍!

     🥇 从零到一学习Python 🌀 带你玩转Python技术流!

     🏆 前沿应用深度测评 🌀 前沿AI产品热门应用在线等你来发掘!

     💦 :本文撰写于CSDN平台,作者:xcLeigh所有权归作者所有)https://xcleigh.blog.csdn.net/,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。


在这里插入图片描述

     📣 亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(或者关注下方公众号,看见后第一时间回复,还有海量编程资料等你来领!),博主看见后一定及时给您答复 💌💌💌

评论 118
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xcLeigh

万水千山总是情,打赏两块行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值