【Python实战进阶】12、Python面向对象编程实战:从零构建搜索引擎,掌握封装、继承与多态!

Python面向对象编程实战:从零构建搜索引擎,掌握封装、继承与多态!

想真正掌握面向对象编程?不如亲手构建一个搜索引擎!本文将通过完整的项目实战,带你深入理解封装、继承、多态等OOP核心概念,让你从"知道"到"会用"的质的飞跃。

1. 为什么用搜索引擎学习面向对象?

搜索引擎是一个完美的OOP学习项目,因为它:

  • 模块化清晰:爬虫、索引、查询、排序各司其职
  • 层次结构明确:文档体系、算法体系自然形成继承树
  • 扩展性强:新文档类型、新搜索算法易于添加
  • 现实意义强:理解工业级系统设计思想

1.1 搜索引擎架构全景图

用户查询 搜索引擎主类 查询处理器 搜索算法体系 关键词搜索 布尔搜索 模糊搜索 文档体系 文本文档 PDF文档 网页文档 倒排索引 文档检索 结果排序 结果展示 数据源 爬虫模块 原始文档

2. 基础架构:面向对象的设计思想

2.1 抽象基类:定义通用接口

python 复制代码
from abc import ABC, abstractmethod
from datetime import datetime

class Document(ABC):
    """文档抽象基类 - 定义所有文档的通用接口"""
    
    def __init__(self, title, content, author="未知"):
        self.title = title
        self._content = content  # 封装:保护内部数据
        self.author = author
        self.created_at = datetime.now()
        self.modified_at = datetime.now()
    
    @abstractmethod
    def parse_content(self):
        """抽象方法 - 强制子类实现内容解析逻辑"""
        pass
    
    @property
    def content(self):
        """封装:通过属性访问器控制数据访问"""
        return self._content
    
    @content.setter
    def content(self, new_content):
        """封装:控制数据修改,自动更新修改时间"""
        self._content = new_content
        self.modified_at = datetime.now()
    
    def get_summary(self, length=100):
        """多态:基类提供默认实现,子类可重写"""
        content = self.parse_content()
        return content[:length] + "..." if len(content) > length else content
    
    def __str__(self):
        return f"{self.__class__.__name__}: {self.title}"

设计思想解析

  • 抽象Document定义通用接口,不关心具体实现
  • 封装_content受保护,通过属性访问器控制
  • 多态准备get_summary为子类重写预留空间

3. 文档体系:继承与多态的完美体现

3.1 文本文档类

python 复制代码
class TextDocument(Document):
    """文本文档类 - 继承自Document基类"""
    
    def parse_content(self):
        """多态:实现抽象方法 - 文本文档直接返回内容"""
        return self._content
    
    def word_count(self):
        """扩展:文本文档特有的方法"""
        return len(self._content.split())
    
    def get_summary(self, length=100):
        """多态:重写父类方法,添加文档类型信息"""
        base_summary = super().get_summary(length)
        return f"[文本] {base_summary} (共{self.word_count()}词)"

3.2 PDF文档类

python 复制代码
import re

class PDFDocument(Document):
    """PDF文档类 - 继承并扩展Document功能"""
    
    def __init__(self, title, content, author="未知", pages=1):
        # 调用父类构造函数
        super().__init__(title, content, author)
        # 扩展:PDF特有属性
        self.pages = pages
        self._metadata = {}
    
    def parse_content(self):
        """多态:PDF特有的内容解析逻辑"""
        # 模拟PDF解析 - 移除特殊字符
        cleaned_content = re.sub(r'[^\w\s]', '', self._content)
        return cleaned_content
    
    def add_metadata(self, key, value):
        """扩展:PDF文档特有的元数据管理"""
        self._metadata[key] = value
    
    def get_summary(self, length=100):
        """多态:重写摘要生成,包含PDF特有信息"""
        base_summary = super().get_summary(length)
        return f"[PDF - {self.pages}页] {base_summary}"

3.3 网页文档类

python 复制代码
class WebPageDocument(Document):
    """网页文档类 - 继承并扩展Document功能"""
    
    def __init__(self, title, content, url, author="未知"):
        super().__init__(title, content, author)
        # 扩展:网页特有属性
        self.url = url
        self.links = []
    
    def parse_content(self):
        """多态:网页内容解析 - 移除HTML标签"""
        cleaned_content = re.sub(r'<[^>]+>', '', self._content)
        return cleaned_content.strip()
    
    def add_link(self, link_url, link_text):
        """扩展:网页特有的链接管理"""
        self.links.append({"url": link_url, "text": link_text})
    
    def get_summary(self, length=100):
        """多态:重写摘要,包含URL信息"""
        base_summary = super().get_summary(length)
        return f"[网页] {base_summary} (来自: {self.url})"

继承体系可视化
<<abstract>> Document -_content +title +author +created_at +modified_at +parse_content() +get_summary() TextDocument +word_count() +parse_content() +get_summary() PDFDocument +pages -_metadata +add_metadata() +parse_content() +get_summary() WebPageDocument +url +links +add_link() +parse_content() +get_summary()

4. 搜索算法:策略模式的经典应用

4.1 算法抽象基类

python 复制代码
class SearchAlgorithm(ABC):
    """搜索算法抽象基类 - 策略模式接口"""
    
    @abstractmethod
    def search(self, query, documents):
        """抽象搜索方法"""
        pass
    
    def rank_results(self, results):
        """通用结果排序方法"""
        return sorted(results, key=lambda x: x['score'], reverse=True)

4.2 关键词搜索算法

python 复制代码
class KeywordSearch(SearchAlgorithm):
    """关键词搜索算法 - 基础但实用"""
    
    def search(self, query, documents):
        results = []
        query_terms = query.lower().split()
        
        for doc in documents:
            score = self._calculate_score(doc, query_terms)
            if score > 0:
                results.append({
                    'document': doc,
                    'score': score,
                    'matches': self._highlight_matches(query_terms, doc.parse_content())
                })
        
        return self.rank_results(results)
    
    def _calculate_score(self, doc, query_terms):
        """封装:评分计算逻辑"""
        score = 0
        parsed_content = doc.parse_content().lower()
        
        for term in query_terms:
            # 内容匹配
            term_count = parsed_content.count(term)
            score += term_count * 2
            
            # 标题匹配额外加分
            if term in doc.title.lower():
                score += 5
        
        return score
    
    def _highlight_matches(self, terms, content):
        """封装:关键词高亮逻辑"""
        highlighted = content
        for term in terms:
            highlighted = re.sub(
                f"({term})", 
                "**\\1**", 
                highlighted, 
                flags=re.IGNORECASE
            )
        return highlighted

4.3 布尔搜索算法

python 复制代码
class BooleanSearch(SearchAlgorithm):
    """布尔搜索算法 - 支持AND, OR, NOT逻辑"""
    
    def search(self, query, documents):
        # 解析布尔逻辑
        if " AND " in query:
            terms = [term.strip() for term in query.split(" AND ")]
            return self._boolean_and_search(terms, documents)
        elif " OR " in query:
            terms = [term.strip() for term in query.split(" OR ")]
            return self._boolean_or_search(terms, documents)
        elif " NOT " in query:
            parts = query.split(" NOT ")
            include_term = parts[0].strip()
            exclude_term = parts[1].strip()
            return self._boolean_not_search(include_term, exclude_term, documents)
        else:
            # 回退到关键词搜索
            return KeywordSearch().search(query, documents)
    
    def _boolean_and_search(self, terms, documents):
        """封装:AND逻辑实现"""
        results = []
        for doc in documents:
            parsed_content = doc.parse_content().lower()
            if all(term.lower() in parsed_content for term in terms):
                score = sum(parsed_content.count(term.lower()) for term in terms)
                results.append({
                    'document': doc,
                    'score': score,
                    'matches': f"匹配所有条件: {', '.join(terms)}"
                })
        return self.rank_results(results)

4.4 模糊搜索算法

python 复制代码
class FuzzySearch(SearchAlgorithm):
    """模糊搜索算法 - 支持拼写纠错"""
    
    def search(self, query, documents):
        results = []
        query_terms = query.lower().split()
        
        for doc in documents:
            score = self._calculate_fuzzy_score(doc, query_terms)
            if score > 0.1:  # 相似度阈值
                results.append({
                    'document': doc,
                    'score': score,
                    'matches': f"模糊匹配度: {score:.2f}"
                })
        
        return self.rank_results(results)
    
    def _calculate_fuzzy_score(self, doc, query_terms):
        """封装:模糊评分计算"""
        total_score = 0
        parsed_content = doc.parse_content().lower()
        
        for term in query_terms:
            best_match = self._find_best_match(term, parsed_content)
            total_score += best_match
        
        return total_score / len(query_terms) if query_terms else 0
    
    def _find_best_match(self, term, content):
        """封装:寻找最佳匹配词"""
        words = content.split()
        if not words:
            return 0
        
        max_similarity = 0
        for word in words:
            similarity = self._calculate_similarity(term, word)
            if similarity > max_similarity:
                max_similarity = similarity
        
        return max_similarity
    
    def _calculate_similarity(self, word1, word2):
        """封装:词相似度计算"""
        if word1 == word2:
            return 1.0
        
        # 简化的相似度算法
        common_chars = len(set(word1) & set(word2))
        return common_chars / max(len(word1), len(word2))

策略模式架构
查询处理器 搜索算法接口 关键词搜索 布尔搜索 模糊搜索 词频统计 标题加分 AND逻辑 OR逻辑 NOT逻辑 相似度计算 模糊匹配 多态优势 算法可替换 易于扩展 统一接口

5. 主搜索引擎:组合艺术的巅峰

5.1 搜索引擎核心类

python 复制代码
class SearchEngine:
    """搜索引擎主类 - 组合各个模块"""
    
    def __init__(self, name="智能搜索引擎"):
        # 封装:内部数据保护
        self.name = name
        self._documents = []  # 文档集合
        self._index = {}      # 倒排索引
        
        # 组合:多种搜索算法
        self._search_algorithms = {
            'keyword': KeywordSearch(),
            'boolean': BooleanSearch(),
            'fuzzy': FuzzySearch()
        }
        
        self._build_index()
    
    def add_document(self, document):
        """添加文档 - 类型安全检查"""
        if not isinstance(document, Document):
            raise ValueError("只能添加Document类型的文档")
        
        self._documents.append(document)
        self._update_index(document)
        print(f"✅ 已添加文档: {document.title}")
    
    def _build_index(self):
        """封装:构建倒排索引"""
        self._index.clear()
        for doc in self._documents:
            self._update_index(doc)
    
    def _update_index(self, document):
        """封装:更新索引逻辑"""
        content = document.parse_content().lower()
        words = set(re.findall(r'\w+', content))
        
        for word in words:
            if word not in self._index:
                self._index[word] = []
            if document not in self._index[word]:
                self._index[word].append(document)
    
    def search(self, query, algorithm='keyword', limit=10):
        """统一搜索接口"""
        if algorithm not in self._search_algorithms:
            available = list(self._search_algorithms.keys())
            raise ValueError(f"不支持的算法: {algorithm}。可用算法: {available}")
        
        print(f"🔍 在 {self.name} 中搜索: '{query}' (算法: {algorithm})")
        print("=" * 60)
        
        search_algorithm = self._search_algorithms[algorithm]
        results = search_algorithm.search(query, self._documents)
        
        return results[:limit]
    
    def get_statistics(self):
        """系统统计信息"""
        doc_types = {}
        for doc in self._documents:
            doc_type = doc.__class__.__name__
            doc_types[doc_type] = doc_types.get(doc_type, 0) + 1
        
        return {
            '总文档数': len(self._documents),
            '文档类型分布': doc_types,
            '索引词项数': len(self._index),
            '可用算法': list(self._search_algorithms.keys())
        }
    
    def __len__(self):
        """支持len()函数"""
        return len(self._documents)
    
    def __str__(self):
        return f"{self.name} (文档数: {len(self)})"

6. 完整实战演示

6.1 创建搜索引擎实例

python 复制代码
def demo_search_engine():
    """搜索引擎完整演示"""
    
    # 1. 创建搜索引擎
    engine = SearchEngine("Python技术文档搜索引擎")
    print(f"🚀 初始化: {engine}")
    print()
    
    # 2. 创建各种类型文档
    documents = [
        TextDocument(
            "Python编程入门", 
            "Python是一种简单易学的编程语言,适合初学者入门。",
            "技术教育专家"
        ),
        TextDocument(
            "机器学习基础教程", 
            "机器学习是人工智能的核心领域,涵盖监督学习和无监督学习。",
            "AI研究员"
        ),
        PDFDocument(
            "深度学习研究进展",
            "深度学习在计算机视觉和自然语言处理领域取得了突破性进展。",
            "深度学习专家",
            25
        ),
        WebPageDocument(
            "Web开发框架比较",
            "Django和Flask是Python最流行的Web框架,各有优缺点。",
            "https://example.com/framework-comparison",
            "全栈开发者"
        ),
        TextDocument(
            "数据科学实战指南",
            "Pandas和NumPy是Python数据科学生态系统的核心库。",
            "数据科学家"
        )
    ]
    
    # 3. 添加文档到搜索引擎
    for doc in documents:
        engine.add_document(doc)
    
    # 添加PDF元数据和网页链接
    documents[2].add_metadata("研究领域", "计算机视觉")
    documents[3].add_link("https://django.org", "Django官网")
    documents[3].add_link("https://flask.org", "Flask官网")
    
    print()
    
    # 4. 显示系统统计
    stats = engine.get_statistics()
    print("📊 系统统计信息:")
    for key, value in stats.items():
        print(f"   {key}: {value}")
    print()
    
    # 5. 执行多种搜索测试
    test_cases = [
        ("Python", "keyword", "基础关键词搜索"),
        ("机器学习 AND 深度学习", "boolean", "布尔AND搜索"),
        ("Pithon编程", "fuzzy", "模糊搜索(拼写纠错)"),
        ("Django OR Flask", "boolean", "布尔OR搜索"),
        ("数据科学 NOT 机器学习", "boolean", "布尔NOT搜索")
    ]
    
    for query, algorithm, description in test_cases:
        print(f"🧪 测试: {description}")
        print(f"   查询: '{query}' | 算法: {algorithm}")
        
        results = engine.search(query, algorithm)
        
        if results:
            for i, result in enumerate(results, 1):
                doc = result['document']
                print(f"   {i}. [{doc.__class__.__name__}] {doc.title}")
                print(f"      评分: {result['score']:.2f}")
                print(f"      摘要: {doc.get_summary(40)}")
                if 'matches' in result:
                    print(f"      匹配: {result['matches']}")
                print()
        else:
            print("   ❌ 没有找到相关结果")
        
        print("   " + "-" * 50)
    
    return engine

# 运行演示
if __name__ == "__main__":
    engine = demo_search_engine()

6.2 预期输出示例

复制代码
🚀 初始化: Python技术文档搜索引擎 (文档数: 0)

✅ 已添加文档: Python编程入门
✅ 已添加文档: 机器学习基础教程
✅ 已添加文档: 深度学习研究进展
✅ 已添加文档: Web开发框架比较
✅ 已添加文档: 数据科学实战指南

📊 系统统计信息:
   总文档数: 5
   文档类型分布: {'TextDocument': 3, 'PDFDocument': 1, 'WebPageDocument': 1}
   索引词项数: 45
   可用算法: ['keyword', 'boolean', 'fuzzy']

🧪 测试: 基础关键词搜索
   查询: 'Python' | 算法: keyword
🔍 在 Python技术文档搜索引擎 中搜索: 'Python' (算法: keyword)
============================================================
   1. [TextDocument] Python编程入门
      评分: 7.00
      摘要: [文本] Python是一种简单易学的编程语言,适合初学... (共8词)
      匹配: **Python**是一种简单易学的**python**编程语言,适合初学者入门。

   2. [WebPageDocument] Web开发框架比较
      评分: 2.00
      摘要: [网页] Django和Flask是Python最流行的Web框架... (来自: https://example.com/framework-comparison)
      匹配: Django和Flask是**Python**最流行的Web框架,各有优缺点。

7. 面向对象设计思想总结

7.1 封装:数据保护与接口设计

python 复制代码
# 好的封装示例
class SearchEngine:
    def __init__(self):
        self._documents = []  # 内部数据保护
        self._index = {}      # 实现细节隐藏
    
    def add_document(self, document):  # 统一接口
        # 参数验证和业务逻辑封装
        pass
    
    def _build_index(self):  # 私有方法,内部实现
        pass

7.2 继承:代码复用与层次结构

Document TextDocument PDFDocument WebPageDocument SearchAlgorithm KeywordSearch BooleanSearch FuzzySearch 继承优势 代码复用 多态支持 易于扩展

7.3 多态:统一接口,不同实现

python 复制代码
# 多态的魅力
documents = [TextDocument(...), PDFDocument(...), WebPageDocument(...)]

for doc in documents:
    # 同一接口,不同行为
    content = doc.parse_content()  # 每个文档类型有自己的解析逻辑
    summary = doc.get_summary()    # 每个文档类型有自己的摘要生成方式

7.4 组合:构建复杂系统

python 复制代码
class SearchEngine:
    def __init__(self):
        # 组合多个独立模块
        self._documents = []           # 文档集合
        self._search_algorithms = {    # 算法集合
            'keyword': KeywordSearch(),
            'boolean': BooleanSearch(),
            'fuzzy': FuzzySearch()
        }

8. 项目扩展思路

8.1 添加新文档类型

python 复制代码
class ExcelDocument(Document):
    """Excel文档类 - 扩展新的文档类型"""
    
    def __init__(self, title, content, author="未知", sheets=1):
        super().__init__(title, content, author)
        self.sheets = sheets
        self._data_frames = []
    
    def parse_content(self):
        """多态:Excel特有的解析逻辑"""
        # 使用pandas解析Excel数据
        return "\n".join([f"Sheet{i}: {len(df)}行" for i, df in enumerate(self._data_frames)])
    
    def add_data_frame(self, data_frame):
        """扩展:Excel特有的数据处理"""
        self._data_frames.append(data_frame)

8.2 添加新搜索算法

python 复制代码
class VectorSearch(SearchAlgorithm):
    """向量搜索算法 - 扩展新的搜索方式"""
    
    def search(self, query, documents):
        # 使用词向量计算语义相似度
        query_vector = self._text_to_vector(query)
        results = []
        
        for doc in documents:
            doc_vector = self._text_to_vector(doc.parse_content())
            similarity = self._cosine_similarity(query_vector, doc_vector)
            
            if similarity > 0.3:
                results.append({
                    'document': doc,
                    'score': similarity,
                    'matches': f"语义相似度: {similarity:.3f}"
                })
        
        return self.rank_results(results)

8.3 性能优化扩展

python 复制代码
class CachedSearchEngine(SearchEngine):
    """带缓存的搜索引擎 - 通过继承扩展功能"""
    
    def __init__(self, name="缓存搜索引擎", cache_size=100):
        super().__init__(name)
        self._cache = {}
        self._cache_size = cache_size
    
    def search(self, query, algorithm='keyword', limit=10):
        # 缓存键
        cache_key = f"{query}_{algorithm}_{limit}"
        
        # 检查缓存
        if cache_key in self._cache:
            print("💾 缓存命中!")
            return self._cache[cache_key]
        
        # 执行搜索并缓存结果
        results = super().search(query, algorithm, limit)
        self._cache[cache_key] = results
        
        # 缓存清理
        if len(self._cache) > self._cache_size:
            self._cache.pop(next(iter(self._cache)))
        
        return results

9. 总结与收获

通过这个搜索引擎项目,我们实践了:

🎯 面向对象核心概念

  • 封装:保护内部数据,提供统一接口
  • 继承:建立层次结构,实现代码复用
  • 多态:统一接口,不同实现
  • 组合:构建复杂系统

🚀 设计模式应用

  • 策略模式:可互换的搜索算法
  • 模板方法模式:Document基类定义算法骨架
  • 工厂模式:统一的文档创建接口

💡 工程实践价值

  • 模块化设计,易于维护和扩展
  • 接口清晰,便于团队协作
  • 代码复用,减少重复开发
  • 类型安全,减少运行时错误
相关推荐
mortimer1 小时前
Python + FFmpeg 视频自动化处理指南:从硬件加速到精确剪辑
python·ffmpeg·音视频开发
帅得不敢出门1 小时前
Android8 Framework实现Ntp服务器多域名轮询同步时间
android·java·服务器·python·framework·github
阿杰同学1 小时前
Java NIO 面试题及答案整理,最新面试题
java·开发语言·nio
haiyu_y1 小时前
Day 29 异常处理
python
CoderYanger1 小时前
动态规划算法-路径问题:7.礼物的最大价值
开发语言·算法·leetcode·动态规划·1024程序员节
古城小栈1 小时前
Python 3.14:重塑开发体验的五大技术突破与实践指南
开发语言·python
小糖学代码1 小时前
LLM系列:1.python入门:1.初识python
服务器·开发语言·人工智能·python·ai
wadesir1 小时前
掌握 Rust 中的浮点数处理(Rust f64 浮点数与标准库详解)
开发语言·后端·rust