
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基类定义算法骨架
- 工厂模式:统一的文档创建接口
💡 工程实践价值
- 模块化设计,易于维护和扩展
- 接口清晰,便于团队协作
- 代码复用,减少重复开发
- 类型安全,减少运行时错误