第一篇文章
+ +这是第一篇文章的内容...
+ +diff --git a/.gitignore b/.gitignore
index 670cd025a..58330892c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,12 @@ docs/java/*.md
docs/java/*.java
deploy.sh
package.json
-spring-cloud/*
\ No newline at end of file
+spring-cloud/*
+/java/*.java
+/java/nacos/*.*
+#目录下java文件夹
+/java/*.java
+#目录下java文件夹所有内容
+/java/*.*
+.temp
+.cache
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..10b731c51
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
diff --git a/.idea/JavaPlusDoc.iml b/.idea/JavaPlusDoc.iml
new file mode 100644
index 000000000..24643cc37
--- /dev/null
+++ b/.idea/JavaPlusDoc.iml
@@ -0,0 +1,12 @@
+
+
如果您觉得本文档对您的学习和工作有所帮助,欢迎扫描下方二维码进行打赏支持。您的每一份鼓励都是我们持续创作优质内容的动力!
+
+ 感谢您的支持与鼓励!
+您的赞助将用于平台维护、内容更新与技术研究
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
tryReserveStock → createOrder → confirmStock 三阶段,失败时触发补偿;idempotencyKey,并在数据库做唯一索引;重复请求自动短路返回上次结果。RpcClient,根据配置动态选择 gRPC 或 HTTP,并自动埋点监控调用时延、错误率。段落内容
链接" + + # 提取所有标签内容 + tag_content_pattern = r"<[^>]+>(.*?)[^>]+>" + contents = re.findall(tag_content_pattern, html) + print(f"HTML内容: {contents}") + + # 提取特定标签 + h1_pattern = r"这是一个段落。
+ 链接文本 +
+
+
+ """
+
+ # 提取所有标签
+ all_tags = re.findall(r"<[^>]+>", html_content)
+ print(f"所有标签: {all_tags[:5]}...") # 只显示前5个
+
+ # 提取标签内容
+ tag_contents = re.findall(r"<(\w+)[^>]*>(.*?)\1>", html_content, re.DOTALL)
+ print("标签内容:")
+ for tag, content in tag_contents:
+ clean_content = content.strip()
+ if clean_content and not clean_content.startswith('<'):
+ print(f" {tag}: {clean_content}")
+
+ # 提取链接
+ links = re.findall(r']+href="([^"]+)"[^>]*>(.*?)', html_content)
+ print(f"链接: {links}")
+
+ # 提取图片信息
+ images = re.findall(r'这是第一篇文章的内容...
+ +这是第二篇文章的内容...
+ +Python 3.12 带来了许多新特性和改进...
+ 2023-10-01 + +最新的机器学习算法在各个领域都有突破...
+ 2023-10-02 + +2023年Web开发的主要趋势和技术栈...
+ 2023-10-03 + +这是一封使用Python发送的HTML格式邮件。
+ +| 项目 | +值 | +
|---|---|
| 发送时间 | +{} | +
| 编程语言 | +Python | +
| 协议 | +SMTP | +
访问我们的网站:Python官网
+这是一封包含内嵌图片的HTML邮件。
+ +图片已内嵌在邮件中,无需额外下载。
+ + + """ + + # 添加HTML内容 + html_part = MIMEText(html_content, 'html', 'utf-8') + message.attach(html_part) + + # 模拟添加内嵌图片 + embedded_images = [ + {"cid": "screenshot", "file": "screenshot.png", "desc": "项目截图"}, + {"cid": "logo", "file": "logo.png", "desc": "公司Logo"} + ] + + print(" 内嵌图片信息:") + for img in embedded_images: + print(f" CID: {img['cid']} -> {img['file']} ({img['desc']})") + + # 实际使用时的代码示例 + print(f" # 添加内嵌图片的代码:") + print(f" # with open('{img['file']}', 'rb') as f:") + print(f" # img_data = f.read()") + print(f" # image = MIMEImage(img_data)") + print(f" # image.add_header('Content-ID', '<{img['cid']}>')") + print(f" # message.attach(image)") + + return message + + # 4. 附件安全检查 + print("\n4. 附件安全检查:") + + def check_attachment_security(file_path): + """检查附件安全性""" + if not os.path.exists(file_path): + return False, "文件不存在" + + filename = os.path.basename(file_path) + file_ext = os.path.splitext(filename)[1].lower() + file_size = os.path.getsize(file_path) + + # 危险文件扩展名 + dangerous_extensions = { + '.exe', '.bat', '.cmd', '.com', '.pif', '.scr', '.vbs', '.js', + '.jar', '.msi', '.dll', '.sys', '.drv', '.ocx' + } + + # 检查文件扩展名 + if file_ext in dangerous_extensions: + return False, f"危险的文件类型: {file_ext}" + + # 检查文件大小(25MB限制) + max_size = 25 * 1024 * 1024 + if file_size > max_size: + return False, f"文件过大: {file_size/1024/1024:.2f}MB > 25MB" + + # 检查文件名 + if len(filename) > 255: + return False, "文件名过长" + + # 检查特殊字符 + invalid_chars = '<>:"/\\|?*' + if any(char in filename for char in invalid_chars): + return False, "文件名包含非法字符" + + return True, "文件安全" + + # 测试安全检查 + test_files = [ + "document.txt", + "image.png", + "script.exe", # 危险文件 + "very_long_filename_" + "x" * 250 + ".txt", # 文件名过长 + "file亲爱的学员,
+我们的Python课程已经更新。
+请访问 课程页面 查看详情。
+
+ 联系电话:123-456-7890
+网站:www.example.com
+ + + """ + + parsed_html = parse_html_email(sample_html) + if parsed_html: + extract_urls_from_text(parsed_html['text']) + extract_phone_numbers(parsed_html['text']) + + # 测试地址解析 + test_addresses = [ + '"张三"明天下午2点开会,请准时参加。
', + 'size': 1024, + 'attachments': [ + { + 'filename': 'agenda.pdf', + 'content_type': 'application/pdf', + 'content': b'PDF content here' + } + ] + }, + { + 'message_id': 'msg002@example.com', + 'from': 'sender2@example.com', + 'to': ['recipient@example.com'], + 'subject': '项目进度报告', + 'date': '2024-01-16T14:20:00', + 'body_text': '本周项目进度如下...', + 'body_html': '本周项目进度如下...
', + 'size': 2048 + } + ] + + # 备份邮件 + print(" 备份邮件:") + for email in test_emails: + backup_system.backup_email(email) + + # 重复备份测试(应该跳过) + print("\n 重复备份测试:") + backup_system.backup_email(test_emails[0]) + + # 搜索测试 + print("\n 搜索测试:") + results = backup_system.search_emails('会议', 'subject') + print(f" 找到 {len(results)} 封包含'会议'的邮件") + + # 导出测试 + print("\n 导出测试:") + json_file = backup_system.export_emails('json') + + # 统计信息 + print("\n 备份统计:") + stats = backup_system.get_backup_stats() + print(f" 总邮件数: {stats['total_emails']}") + print(f" 总大小: {stats['total_size']} 字节") + print(f" 附件数: {stats['total_attachments']}") + print(f" 日期范围: {stats['date_range'][0]} 至 {stats['date_range'][1]}") + + test_backup_system() + +# 运行邮件备份演示 +email_backup_demo() +``` + +### 5.2 邮件监控系统 + +```python +import time +import threading +from datetime import datetime, timedelta +import logging + +def email_monitoring_demo(): + """邮件监控系统演示""" + print("=== 邮件监控系统演示 ===") + + # 1. 邮件监控类 + print("\n1. 邮件监控系统:") + + class EmailMonitor: + """邮件监控系统""" + + def __init__(self, check_interval=60): + self.check_interval = check_interval # 检查间隔(秒) + self.is_running = False + self.monitor_thread = None + self.alerts = [] + self.rules = [] + self.stats = { + 'total_checked': 0, + 'alerts_triggered': 0, + 'last_check': None + } + + # 配置日志 + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' + ) + self.logger = logging.getLogger(__name__) + + def add_rule(self, name, condition, alert_type, threshold=None): + """添加监控规则""" + rule = { + 'name': name, + 'condition': condition, + 'alert_type': alert_type, + 'threshold': threshold, + 'enabled': True, + 'last_triggered': None, + 'trigger_count': 0 + } + self.rules.append(rule) + print(f" ✓ 添加监控规则: {name}") + + def start_monitoring(self): + """开始监控""" + if self.is_running: + print(" 监控已在运行中") + return + + self.is_running = True + self.monitor_thread = threading.Thread(target=self._monitor_loop) + self.monitor_thread.daemon = True + self.monitor_thread.start() + + print(f" ✓ 开始邮件监控,检查间隔: {self.check_interval} 秒") + + def stop_monitoring(self): + """停止监控""" + self.is_running = False + if self.monitor_thread: + self.monitor_thread.join(timeout=5) + + print(" ✓ 停止邮件监控") + + def _monitor_loop(self): + """监控循环""" + while self.is_running: + try: + self._check_emails() + self.stats['last_check'] = datetime.now().isoformat() + time.sleep(self.check_interval) + except Exception as e: + self.logger.error(f"监控检查失败: {e}") + time.sleep(self.check_interval) + + def _check_emails(self): + """检查邮件""" + # 模拟获取新邮件 + new_emails = self._fetch_new_emails() + self.stats['total_checked'] += len(new_emails) + + for email in new_emails: + self._evaluate_rules(email) + + def _fetch_new_emails(self): + """获取新邮件(模拟)""" + # 这里应该连接到实际的邮件服务器 + # 为演示目的,返回模拟数据 + import random + + if random.random() < 0.3: # 30% 概率有新邮件 + return [ + { + 'from': random.choice([ + 'important@company.com', + 'spam@suspicious.com', + 'client@customer.com' + ]), + 'subject': random.choice([ + '紧急:系统故障', + '免费赠品!', + '会议邀请', + '发票确认' + ]), + 'size': random.randint(1000, 100000), + 'date': datetime.now().isoformat(), + 'body': '邮件内容...' + } + ] + return [] + + def _evaluate_rules(self, email): + """评估监控规则""" + for rule in self.rules: + if not rule['enabled']: + continue + + if self._check_rule_condition(email, rule): + self._trigger_alert(email, rule) + + def _check_rule_condition(self, email, rule): + """检查规则条件""" + condition = rule['condition'] + condition_type = condition['type'] + + if condition_type == 'sender_suspicious': + suspicious_domains = condition.get('domains', []) + sender = email.get('from', '') + return any(domain in sender for domain in suspicious_domains) + + elif condition_type == 'large_email': + threshold = rule.get('threshold', 10 * 1024 * 1024) # 10MB + return email.get('size', 0) > threshold + + elif condition_type == 'keyword_alert': + keywords = condition.get('keywords', []) + text = f"{email.get('subject', '')} {email.get('body', '')}" + return any(keyword.lower() in text.lower() for keyword in keywords) + + elif condition_type == 'high_volume': + # 检查短时间内的邮件量 + threshold = rule.get('threshold', 10) + time_window = condition.get('time_window', 300) # 5分钟 + + # 这里应该检查实际的邮件量 + # 为演示目的,随机返回 + import random + return random.random() < 0.1 # 10% 概率触发 + + return False + + def _trigger_alert(self, email, rule): + """触发警报""" + alert = { + 'id': len(self.alerts) + 1, + 'rule_name': rule['name'], + 'alert_type': rule['alert_type'], + 'email_info': { + 'from': email.get('from', ''), + 'subject': email.get('subject', ''), + 'date': email.get('date', '') + }, + 'triggered_at': datetime.now().isoformat(), + 'severity': self._get_alert_severity(rule['alert_type']) + } + + self.alerts.append(alert) + rule['last_triggered'] = alert['triggered_at'] + rule['trigger_count'] += 1 + self.stats['alerts_triggered'] += 1 + + # 记录日志 + self.logger.warning( + f"警报触发: {rule['name']} - {email.get('subject', 'No Subject')}" + ) + + # 发送通知 + self._send_notification(alert) + + def _get_alert_severity(self, alert_type): + """获取警报严重级别""" + severity_map = { + 'security': 'HIGH', + 'spam': 'MEDIUM', + 'volume': 'MEDIUM', + 'size': 'LOW', + 'keyword': 'MEDIUM' + } + return severity_map.get(alert_type, 'LOW') + + def _send_notification(self, alert): + """发送通知""" + # 这里可以实现各种通知方式: + # - 邮件通知 + # - 短信通知 + # - 即时消息 + # - 系统通知 + + print(f" 🚨 {alert['severity']} 警报: {alert['rule_name']}") + print(f" 邮件: {alert['email_info']['subject']}") + print(f" 发件人: {alert['email_info']['from']}") + + def get_alerts(self, severity=None, limit=None): + """获取警报列表""" + alerts = self.alerts + + if severity: + alerts = [a for a in alerts if a['severity'] == severity] + + if limit: + alerts = alerts[-limit:] + + return alerts + + def clear_alerts(self, older_than_days=None): + """清理警报""" + if older_than_days: + cutoff_date = datetime.now() - timedelta(days=older_than_days) + cutoff_str = cutoff_date.isoformat() + + original_count = len(self.alerts) + self.alerts = [ + alert for alert in self.alerts + if alert['triggered_at'] > cutoff_str + ] + cleared_count = original_count - len(self.alerts) + print(f" ✓ 清理了 {cleared_count} 个旧警报") + else: + cleared_count = len(self.alerts) + self.alerts = [] + print(f" ✓ 清理了所有 {cleared_count} 个警报") + + def get_stats(self): + """获取监控统计""" + stats = self.stats.copy() + stats.update({ + 'active_rules': len([r for r in self.rules if r['enabled']]), + 'total_rules': len(self.rules), + 'pending_alerts': len(self.alerts), + 'is_running': self.is_running + }) + return stats + + # 2. 配置监控规则 + print("\n2. 配置监控规则:") + + def setup_monitoring_rules(): + """设置监控规则""" + monitor = EmailMonitor(check_interval=5) # 5秒检查一次(演示用) + + # 可疑发件人监控 + monitor.add_rule( + "可疑发件人检测", + { + 'type': 'sender_suspicious', + 'domains': ['suspicious.com', 'spam.net', 'phishing.org'] + }, + 'security' + ) + + # 大邮件监控 + monitor.add_rule( + "大邮件检测", + { + 'type': 'large_email' + }, + 'size', + threshold=5 * 1024 * 1024 # 5MB + ) + + # 关键词警报 + monitor.add_rule( + "敏感关键词检测", + { + 'type': 'keyword_alert', + 'keywords': ['紧急', '故障', '病毒', '攻击', 'urgent', 'critical'] + }, + 'keyword' + ) + + # 邮件量异常监控 + monitor.add_rule( + "邮件量异常检测", + { + 'type': 'high_volume', + 'time_window': 300 # 5分钟 + }, + 'volume', + threshold=20 # 5分钟内超过20封 + ) + + return monitor + + # 3. 测试监控系统 + print("\n3. 测试监控系统:") + + def test_monitoring_system(): + """测试监控系统""" + monitor = setup_monitoring_rules() + + # 开始监控 + monitor.start_monitoring() + + print(" 监控运行中,等待警报...") + + # 运行一段时间 + time.sleep(15) + + # 检查统计 + stats = monitor.get_stats() + print(f"\n 监控统计:") + print(f" 检查的邮件数: {stats['total_checked']}") + print(f" 触发的警报数: {stats['alerts_triggered']}") + print(f" 活跃规则数: {stats['active_rules']}") + print(f" 最后检查时间: {stats['last_check']}") + + # 显示警报 + alerts = monitor.get_alerts() + if alerts: + print(f"\n 最近的警报:") + for alert in alerts[-5:]: # 显示最近5个 + print(f" {alert['severity']} - {alert['rule_name']}") + print(f" {alert['email_info']['subject']}") + + # 停止监控 + monitor.stop_monitoring() + + test_monitoring_system() + +# 运行邮件监控演示 +email_monitoring_demo() +``` + +## 6. 最佳实践和安全 + +### 6.1 邮件安全最佳实践 + +```python +import ssl +import base64 +from cryptography.fernet import Fernet +import keyring + +def email_security_demo(): + """邮件安全最佳实践演示""" + print("=== 邮件安全最佳实践演示 ===") + + # 1. 安全连接配置 + print("\n1. 安全连接配置:") + + def create_secure_smtp_connection(): + """创建安全的SMTP连接""" + import smtplib + + # 创建SSL上下文 + context = ssl.create_default_context() + + # 配置SSL选项 + context.check_hostname = True + context.verify_mode = ssl.CERT_REQUIRED + + # 禁用不安全的协议 + context.options |= ssl.OP_NO_SSLv2 + context.options |= ssl.OP_NO_SSLv3 + context.options |= ssl.OP_NO_TLSv1 + context.options |= ssl.OP_NO_TLSv1_1 + + print(" ✓ 创建安全SSL上下文") + + try: + # 使用SMTP_SSL直接建立加密连接 + server = smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) + print(" ✓ 建立SSL加密连接") + + # 或者使用STARTTLS + # server = smtplib.SMTP('smtp.gmail.com', 587) + # server.starttls(context=context) + + return server + + except Exception as e: + print(f" ✗ 连接失败: {e}") + return None + + def create_secure_imap_connection(): + """创建安全的IMAP连接""" + import imaplib + + # 创建SSL上下文 + context = ssl.create_default_context() + + try: + # 使用IMAP4_SSL + server = imaplib.IMAP4_SSL('imap.gmail.com', 993, ssl_context=context) + print(" ✓ 建立IMAP SSL连接") + return server + + except Exception as e: + print(f" ✗ IMAP连接失败: {e}") + return None + + # 测试安全连接 + smtp_server = create_secure_smtp_connection() + if smtp_server: + smtp_server.quit() + + imap_server = create_secure_imap_connection() + if imap_server: + imap_server.logout() + + # 2. 密码安全管理 + print("\n2. 密码安全管理:") + + class SecureCredentialManager: + """安全凭据管理器""" + + def __init__(self, service_name="email_client"): + self.service_name = service_name + + def store_credentials(self, username, password): + """安全存储凭据""" + try: + # 使用系统密钥环存储密码 + keyring.set_password(self.service_name, username, password) + print(f" ✓ 安全存储凭据: {username}") + return True + except Exception as e: + print(f" ✗ 存储失败: {e}") + return False + + def get_credentials(self, username): + """获取存储的凭据""" + try: + password = keyring.get_password(self.service_name, username) + if password: + print(f" ✓ 获取凭据: {username}") + return password + else: + print(f" ✗ 未找到凭据: {username}") + return None + except Exception as e: + print(f" ✗ 获取失败: {e}") + return None + + def delete_credentials(self, username): + """删除存储的凭据""" + try: + keyring.delete_password(self.service_name, username) + print(f" ✓ 删除凭据: {username}") + return True + except Exception as e: + print(f" ✗ 删除失败: {e}") + return False + + def encrypt_data(self, data): + """加密敏感数据""" + # 生成密钥 + key = Fernet.generate_key() + cipher = Fernet(key) + + # 加密数据 + encrypted_data = cipher.encrypt(data.encode()) + + print(" ✓ 数据已加密") + return key, encrypted_data + + def decrypt_data(self, key, encrypted_data): + """解密数据""" + try: + cipher = Fernet(key) + decrypted_data = cipher.decrypt(encrypted_data) + print(" ✓ 数据已解密") + return decrypted_data.decode() + except Exception as e: + print(f" ✗ 解密失败: {e}") + return None + + # 测试凭据管理 + cred_manager = SecureCredentialManager() + + # 注意:实际使用时不要在代码中硬编码密码 + test_username = "test@example.com" + test_password = "secure_password_123" + + # 存储和获取凭据(仅演示,实际环境中谨慎使用) + # cred_manager.store_credentials(test_username, test_password) + # retrieved_password = cred_manager.get_credentials(test_username) + + # 测试数据加密 + sensitive_data = "这是敏感的邮件内容" + key, encrypted = cred_manager.encrypt_data(sensitive_data) + decrypted = cred_manager.decrypt_data(key, encrypted) + + # 3. 邮件内容安全 + print("\n3. 邮件内容安全:") + + class EmailSecurityValidator: + """邮件安全验证器""" + + def __init__(self): + self.suspicious_patterns = [ + r'(?i)password.*reset', + r'(?i)click.*here.*urgent', + r'(?i)verify.*account.*immediately', + r'(?i)suspended.*account', + r'(?i)winner.*lottery', + r'(?i)free.*money', + r'(?i)nigerian.*prince' + ] + + self.safe_domains = [ + 'gmail.com', 'outlook.com', 'yahoo.com', + 'company.com' # 添加你信任的域名 + ] + + def validate_sender(self, sender_email): + """验证发件人""" + import re + + # 检查邮箱格式 + email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + if not re.match(email_pattern, sender_email): + return False, "邮箱格式无效" + + # 检查域名 + domain = sender_email.split('@')[1] + if domain in self.safe_domains: + return True, "可信域名" + + # 检查可疑域名特征 + suspicious_domain_patterns = [ + r'.*\d{4,}.*', # 包含4位以上数字 + r'.*-.*-.*', # 多个连字符 + r'.{20,}', # 域名过长 + ] + + for pattern in suspicious_domain_patterns: + if re.match(pattern, domain): + return False, f"可疑域名模式: {pattern}" + + return True, "域名检查通过" + + def scan_content(self, subject, body): + """扫描邮件内容""" + import re + + content = f"{subject} {body}" + threats = [] + + # 检查可疑模式 + for pattern in self.suspicious_patterns: + if re.search(pattern, content): + threats.append(f"可疑模式: {pattern}") + + # 检查URL + url_pattern = r'https?://[^\s]+' + urls = re.findall(url_pattern, content) + + for url in urls: + if self._is_suspicious_url(url): + threats.append(f"可疑链接: {url}") + + # 检查附件提及 + attachment_patterns = [ + r'(?i)attachment.*exe', + r'(?i)download.*file', + r'(?i)open.*document' + ] + + for pattern in attachment_patterns: + if re.search(pattern, content): + threats.append(f"可疑附件提及: {pattern}") + + return threats + + def _is_suspicious_url(self, url): + """检查URL是否可疑""" + import re + + suspicious_url_patterns = [ + r'.*bit\.ly.*', + r'.*tinyurl.*', + r'.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.*', # IP地址 + r'.*[a-z]{20,}\.[a-z]{2,3}.*', # 随机长域名 + ] + + for pattern in suspicious_url_patterns: + if re.match(pattern, url): + return True + + return False + + def validate_email(self, email_data): + """综合验证邮件""" + results = { + 'is_safe': True, + 'warnings': [], + 'threats': [] + } + + # 验证发件人 + sender_valid, sender_msg = self.validate_sender(email_data.get('from', '')) + if not sender_valid: + results['threats'].append(f"发件人验证失败: {sender_msg}") + results['is_safe'] = False + + # 扫描内容 + content_threats = self.scan_content( + email_data.get('subject', ''), + email_data.get('body', '') + ) + + if content_threats: + results['threats'].extend(content_threats) + results['is_safe'] = False + + # 检查附件 + attachments = email_data.get('attachments', []) + for attachment in attachments: + filename = attachment.get('filename', '') + if self._is_dangerous_attachment(filename): + results['threats'].append(f"危险附件: {filename}") + results['is_safe'] = False + + return results + + def _is_dangerous_attachment(self, filename): + """检查附件是否危险""" + dangerous_extensions = [ + '.exe', '.scr', '.bat', '.cmd', '.com', '.pif', + '.vbs', '.js', '.jar', '.zip', '.rar' + ] + + filename_lower = filename.lower() + return any(filename_lower.endswith(ext) for ext in dangerous_extensions) + + # 测试安全验证 + validator = EmailSecurityValidator() + + # 测试邮件 + test_emails = [ + { + 'from': 'legitimate@company.com', + 'subject': '会议通知', + 'body': '明天下午2点开会', + 'attachments': [] + }, + { + 'from': 'suspicious123456@random-domain.com', + 'subject': 'URGENT: Verify your account immediately!', + 'body': 'Click here to reset your password: http://bit.ly/suspicious', + 'attachments': [{'filename': 'document.exe'}] + } + ] + + print(" 邮件安全验证:") + for i, email in enumerate(test_emails, 1): + print(f"\n 邮件 {i}: {email['subject']}") + result = validator.validate_email(email) + + if result['is_safe']: + print(" ✓ 邮件安全") + else: + print(" ⚠️ 发现威胁:") + for threat in result['threats']: + print(f" • {threat}") + +# 运行邮件安全演示 +email_security_demo() +``` + +## 7. 学习建议和总结 + +### 7.1 学习路径 + +1. **基础知识** + - 理解邮件协议(SMTP、POP3、IMAP) + - 掌握Python邮件模块的基本用法 + - 学习邮件格式和编码 + +2. **进阶应用** + - 邮件内容解析和处理 + - 附件处理和文件操作 + - 邮件过滤和自动化 + +3. **实际项目** + - 构建邮件客户端 + - 实现邮件监控系统 + - 开发邮件备份工具 + +### 7.2 最佳实践 + +1. **安全性** + - 使用SSL/TLS加密连接 + - 安全存储邮箱密码 + - 验证邮件来源和内容 + +2. **性能优化** + - 合理使用连接池 + - 批量处理邮件 + - 异步处理大量邮件 + +3. **错误处理** + - 完善的异常处理机制 + - 重试机制和超时设置 + - 详细的日志记录 + +### 7.3 常见陷阱和解决方案 + +1. **编码问题** + ```python + # 问题:邮件内容乱码 + # 解决:正确处理字符编码 + import chardet + + def decode_email_content(content): + if isinstance(content, bytes): + encoding = chardet.detect(content)['encoding'] + return content.decode(encoding or 'utf-8') + return content + ``` + +2. **连接超时** + ```python + # 问题:邮件服务器连接超时 + # 解决:设置合理的超时时间 + import socket + + # 设置全局超时 + socket.setdefaulttimeout(30) + + # 或在连接时设置 + server = smtplib.SMTP('smtp.gmail.com', 587, timeout=30) + ``` + +3. **内存占用** + ```python + # 问题:处理大量邮件时内存占用过高 + # 解决:使用生成器和流式处理 + def process_emails_efficiently(email_list): + for email in email_list: + # 处理单封邮件 + process_single_email(email) + # 及时释放内存 + del email + ``` + +### 7.4 本章总结 + +本章详细介绍了Python电子邮件编程的各个方面: + +1. **邮件基础**:学习了SMTP、POP3、IMAP协议的基本概念和Python实现 +2. **发送邮件**:掌握了文本邮件、HTML邮件、附件邮件的发送方法 +3. **接收邮件**:学会了连接邮件服务器、下载和解析邮件内容 +4. **邮件处理**:实现了邮件过滤、自动回复、统计分析等高级功能 +5. **实际应用**:构建了邮件备份系统和监控系统 +6. **安全实践**:了解了邮件安全的重要性和实现方法 + +通过本章的学习,你应该能够: +- 使用Python发送和接收各种类型的邮件 +- 解析和处理邮件内容和附件 +- 实现邮件自动化处理功能 +- 构建实用的邮件应用系统 +- 确保邮件操作的安全性 + +邮件编程是Python的重要应用领域,掌握这些技能将为你的项目开发提供强大的通信能力。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Python/2.md b/docs/Python/2.md new file mode 100644 index 000000000..22b8637f1 --- /dev/null +++ b/docs/Python/2.md @@ -0,0 +1,241 @@ +--- +title: 第2天-安装Python +author: 哪吒 +date: '2023-06-15' +--- + +# 第2天-安装Python + +## Python的跨平台特性 + +因为Python是跨平台的,它可以运行在Windows、Mac和各种Linux/Unix系统上。在Windows上写Python程序,放到Linux上也是能够运行的。 + +> **小白注解**:跨平台意味着"一次编写,到处运行",这是Python的一大优势。你不需要为不同的操作系统重写代码。 + +## 安装Python能得到什么? + +要开始学习Python编程,首先就得把Python安装到你的电脑里。安装后,你会得到: + +> **安装包含的组件**: +> - 🐍 **Python解释器**:负责运行Python程序的核心引擎 +> - 💻 **命令行交互环境**:可以直接输入Python代码并立即看到结果 +> - 🛠️ **IDLE**:Python自带的简单集成开发环境 +> - 📚 **标准库**:大量内置的功能模块 +> - 📦 **pip**:Python包管理工具,用于安装第三方库 + +## Python版本选择 + +目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的。由于3.x版越来越普及,教程将以最新的Python 3.x版本为基础。 + +> **版本说明**: +> - **Python 2.x**:已于2020年1月1日停止维护,不建议新项目使用 +> - **Python 3.x**:当前主流版本,持续更新中 +> - **推荐版本**:Python 3.8+ (支持最新特性,稳定性好) + +> **小白提醒**:如果你是初学者,直接选择最新的Python 3.x版本就对了! + +## 在Windows上安装Python + +在Windows上安装Python,有两种方法: + +### 方法一:官方安装包(推荐新手) + +可以直接从Python的官方网站下载Python 3对应的Windows安装程序,推荐下载Windows installer (64-bit),然后,运行下载的python-3.x-amd64.exe安装包: + +> **下载地址**:https://www.python.org/downloads/windows/ + + + +> **⚠️ 重要提醒**:特别要注意勾上"Add Python 3.x to PATH",这样你就可以在任何地方使用python命令了! + +**安装步骤**: +1. 下载安装包 +2. 双击运行安装程序 +3. ✅ **务必勾选**"Add Python to PATH" +4. 点击"Install Now" +5. 等待安装完成 + +**验证安装**: +```bash +C:\Users\23979>python --version +Python 3.13.5 +``` + +> **小白解释**:`python --version`命令用来查看Python版本,如果显示版本号说明安装成功! + +### 方法二:包管理器安装(适合进阶用户) + +先安装一个包管理器,推荐Scoop,然后在PowerShell中通过以下命令安装Python: + +```powershell +# 首先安装Scoop(如果还没有的话) +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +irm get.scoop.sh | iex + +# 然后安装Python +scoop install python +``` + +> **Scoop的优势**: +> - 自动管理PATH环境变量 +> - 可以同时安装多个Python版本 +> - 卸载干净,不留垃圾文件 +> - 命令行操作,适合开发者 + +## 在macOS上安装Python + +如果你正在使用Mac,那么系统自带的Python版本是2.x。要安装最新的Python 3.x,有两个方法: + +### 方法一:官方安装包 +从Python官网下载Python 3 macOS版的安装程序,下载后双击运行并安装。 + +> **下载地址**:https://www.python.org/downloads/macos/ + +### 方法二:Homebrew安装(推荐) +如果安装了包管理器Homebrew,直接通过命令安装: + +```bash +# 安装Python 3 +brew install python + +# 验证安装 +python3 --version +``` + +> **macOS注意事项**: +> - 系统自带的`python`命令指向Python 2.x +> - 新安装的Python 3使用`python3`命令 +> - 建议创建别名:`alias python=python3` + +## 在Linux上安装Python + +大多数Linux发行版都预装了Python,但可能版本较旧。以下是常见发行版的安装方法: + +### Ubuntu/Debian系统 +```bash +# 更新包列表 +sudo apt update + +# 安装Python 3 +sudo apt install python3 python3-pip + +# 验证安装 +python3 --version +``` + +### CentOS/RHEL系统 +```bash +# 安装Python 3 +sudo yum install python3 python3-pip +# 或者在较新版本中使用 +sudo dnf install python3 python3-pip +``` + +### Arch Linux +```bash +# 安装Python 3 +sudo pacman -S python python-pip +``` + +> **Linux小贴士**:如果你正在使用Linux,建议你有一定的系统管理经验。如果完全是新手,建议先从Windows开始学习Python。 + +## 测试Python交互环境 + +安装完成后,打开命令行输入`python`(Windows)或`python3`(macOS/Linux),你会看到类似这样的界面: + +```python +C:\Users\23979>python +Python 3.13.5 (tags/v3.13.5:6cb20a2, Jun 11 2025, 16:15:46) [MSC v.1943 64 bit (AMD64)] on win32 +Type "help", "copyright", "credits" or "license" for more information. +>>> 1+1 +2 +>>> print("Hello, Python!") +Hello, Python! +>>> exit() +``` + +> **交互环境说明**: +> - `>>>`是Python的提示符,表示等待你输入代码 +> - 输入代码后按回车,立即看到结果 +> - 输入`exit()`或按`Ctrl+Z`(Windows)/`Ctrl+D`(macOS/Linux)退出 + +## Python解释器详解 + +当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件。要运行代码,就需要Python解释器去执行.py文件。 + +> **小白理解**:解释器就像一个翻译官,把你写的Python代码翻译成计算机能理解的机器语言。 + +### 多种Python解释器 + +由于整个Python语言从规范到解释器都是开源的,所以理论上,只要水平够高,任何人都可以编写Python解释器来执行Python代码(当然难度很大)。事实上,确实存在多种Python解释器: + +> **主要Python解释器**: +> +> 🔥 **CPython**(官方,推荐) +> - 用C语言开发,最标准的实现 +> - 使用最广泛,兼容性最好 +> - 我们通常说的"Python"就是指CPython +> +> ⚡ **PyPy**(高性能) +> - 用Python自己写的Python解释器 +> - 执行速度比CPython快2-10倍 +> - 适合计算密集型程序 +> +> ☕ **Jython**(Java平台) +> - 运行在Java虚拟机上 +> - 可以调用Java类库 +> - 适合Java环境集成 +> +> 🌐 **IronPython**(.NET平台) +> - 运行在.NET平台上 +> - 可以调用.NET类库 +> - 适合Windows/.NET环境 + +### CPython解释器 + +当我们从Python官方网站下载并安装好Python 3.x后,我们就直接获得了一个官方版本的解释器:CPython。这个解释器是用C语言开发的,所以叫CPython。在命令行下运行python就是启动CPython解释器。 + +CPython是使用最广的Python解释器。教程的所有代码也都在CPython下执行。 + +> **为什么选择CPython?** +> - ✅ 官方标准实现,最稳定可靠 +> - ✅ 第三方库支持最完整 +> - ✅ 文档和社区支持最好 +> - ✅ 适合初学者和生产环境 + +## 常见问题解答 + +> **Q: 安装后找不到python命令怎么办?** +> +> A: 检查是否勾选了"Add Python to PATH"。如果没有,可以: +> 1. 重新安装Python并勾选该选项 +> 2. 手动添加Python安装目录到系统PATH +> 3. 使用完整路径运行:`C:\Python39\python.exe` + +> **Q: python和python3命令有什么区别?** +> +> A: +> - **Windows**:通常都是`python` +> - **macOS/Linux**:`python`可能指向Python 2.x,`python3`指向Python 3.x +> - 建议在macOS/Linux上使用`python3`命令 + +> **Q: 如何同时安装多个Python版本?** +> +> A: +> - 使用**pyenv**(macOS/Linux)或**pyenv-win**(Windows) +> - 使用**Anaconda**管理多个环境 +> - 手动安装到不同目录 + +## 下一步 + +恭喜!你已经成功安装了Python。现在你可以: +- 在命令行中使用Python交互环境 +- 编写并运行你的第一个Python程序 +- 开始学习Python语法 + +> **学习建议**:先熟悉Python交互环境,它是学习和测试代码的好工具。在交互环境中,你可以立即看到代码的执行结果,这对理解Python语法非常有帮助。 + + + + + diff --git a/docs/Python/20.md b/docs/Python/20.md new file mode 100644 index 000000000..b9f0ebb89 --- /dev/null +++ b/docs/Python/20.md @@ -0,0 +1,2756 @@ +--- +title: 第20天-访问数据库 +author: 哪吒 +date: '2023-06-15' +--- + +# 第20天-访问数据库 + +## 1. 数据库基础 + +### 1.1 数据库概述 + +数据库是存储和管理数据的系统,Python提供了多种方式来访问不同类型的数据库。 + +```python +def database_overview_demo(): + """数据库概述演示""" + print("=== 数据库概述演示 ===") + + # 1. 数据库类型 + print("\n1. 常见数据库类型:") + + database_types = { + "关系型数据库": { + "SQLite": "轻量级文件数据库,无需服务器", + "MySQL": "开源关系型数据库管理系统", + "PostgreSQL": "功能强大的开源对象关系数据库", + "Oracle": "企业级商业数据库", + "SQL Server": "微软的关系型数据库" + }, + "NoSQL数据库": { + "MongoDB": "文档型数据库", + "Redis": "内存键值数据库", + "Cassandra": "分布式列族数据库", + "Neo4j": "图形数据库" + } + } + + for category, databases in database_types.items(): + print(f"\n {category}:") + for name, description in databases.items(): + print(f" • {name}: {description}") + + # 2. Python数据库API规范 + print("\n2. Python数据库API规范 (DB-API 2.0):") + + api_components = { + "连接对象 (Connection)": "表示数据库连接", + "游标对象 (Cursor)": "执行SQL语句和获取结果", + "异常类型": "处理数据库相关错误", + "类型构造器": "处理特殊数据类型" + } + + for component, description in api_components.items(): + print(f" • {component}: {description}") + + # 3. 常用Python数据库模块 + print("\n3. 常用Python数据库模块:") + + python_modules = { + "sqlite3": "Python内置SQLite模块", + "pymysql": "纯Python MySQL客户端", + "psycopg2": "PostgreSQL适配器", + "cx_Oracle": "Oracle数据库接口", + "pymongo": "MongoDB Python驱动", + "redis-py": "Redis Python客户端" + } + + for module, description in python_modules.items(): + print(f" • {module}: {description}") + + # 4. 数据库操作基本流程 + print("\n4. 数据库操作基本流程:") + + basic_flow = [ + "1. 导入数据库模块", + "2. 建立数据库连接", + "3. 创建游标对象", + "4. 执行SQL语句", + "5. 处理查询结果", + "6. 提交事务(如需要)", + "7. 关闭游标和连接" + ] + + for step in basic_flow: + print(f" {step}") + + # 5. 基本SQL语句回顾 + print("\n5. 基本SQL语句回顾:") + + sql_examples = { + "创建表": "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)", + "插入数据": "INSERT INTO users (name, email) VALUES ('张三', 'zhang@example.com')", + "查询数据": "SELECT * FROM users WHERE name = '张三'", + "更新数据": "UPDATE users SET email = 'new@example.com' WHERE id = 1", + "删除数据": "DELETE FROM users WHERE id = 1" + } + + for operation, sql in sql_examples.items(): + print(f" {operation}:") + print(f" {sql}") + +# 运行数据库概述演示 +database_overview_demo() +``` + +## 2. SQLite数据库 + +### 2.1 SQLite基础操作 + +```python +import sqlite3 +import os +from datetime import datetime + +def sqlite_basic_demo(): + """SQLite基础操作演示""" + print("=== SQLite基础操作演示 ===") + + # 1. 连接数据库 + print("\n1. 连接SQLite数据库:") + + # 连接到数据库文件(如果不存在会自动创建) + db_path = 'example.db' + conn = sqlite3.connect(db_path) + print(f" ✓ 连接到数据库: {db_path}") + + # 创建游标 + cursor = conn.cursor() + print(" ✓ 创建游标对象") + + # 2. 创建表 + print("\n2. 创建数据表:") + + # 用户表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL UNIQUE, + email TEXT NOT NULL, + password TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT 1 + ) + ''') + print(" ✓ 创建用户表") + + # 文章表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS articles ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + content TEXT, + author_id INTEGER, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (author_id) REFERENCES users (id) + ) + ''') + print(" ✓ 创建文章表") + + # 3. 插入数据 + print("\n3. 插入数据:") + + # 插入单条记录 + try: + cursor.execute( + "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", + ('张三', 'zhangsan@example.com', 'password123') + ) + print(" ✓ 插入用户: 张三") + except sqlite3.IntegrityError as e: + print(f" 用户已存在: {e}") + + # 插入多条记录 + users_data = [ + ('李四', 'lisi@example.com', 'password456'), + ('王五', 'wangwu@example.com', 'password789'), + ('赵六', 'zhaoliu@example.com', 'passwordabc') + ] + + try: + cursor.executemany( + "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", + users_data + ) + print(f" ✓ 批量插入 {len(users_data)} 个用户") + except sqlite3.IntegrityError as e: + print(f" 部分用户已存在: {e}") + + # 提交事务 + conn.commit() + print(" ✓ 提交事务") + + # 4. 查询数据 + print("\n4. 查询数据:") + + # 查询所有用户 + cursor.execute("SELECT * FROM users") + users = cursor.fetchall() + print(f" 查询到 {len(users)} 个用户:") + for user in users: + print(f" ID: {user[0]}, 用户名: {user[1]}, 邮箱: {user[2]}") + + # 条件查询 + cursor.execute("SELECT id, username FROM users WHERE username LIKE ?", ('%张%',)) + filtered_users = cursor.fetchall() + print(f"\n 姓张的用户 ({len(filtered_users)} 个):") + for user in filtered_users: + print(f" ID: {user[0]}, 用户名: {user[1]}") + + # 使用fetchone获取单条记录 + cursor.execute("SELECT * FROM users WHERE username = ?", ('李四',)) + user = cursor.fetchone() + if user: + print(f"\n 找到用户: {user[1]} ({user[2]})") + + # 5. 更新数据 + print("\n5. 更新数据:") + + cursor.execute( + "UPDATE users SET email = ? WHERE username = ?", + ('zhangsan_new@example.com', '张三') + ) + affected_rows = cursor.rowcount + print(f" ✓ 更新了 {affected_rows} 条记录") + + conn.commit() + + # 6. 删除数据 + print("\n6. 删除数据:") + + cursor.execute("DELETE FROM users WHERE username = ?", ('赵六',)) + deleted_rows = cursor.rowcount + print(f" ✓ 删除了 {deleted_rows} 条记录") + + conn.commit() + + # 7. 查看表结构 + print("\n7. 查看表结构:") + + cursor.execute("PRAGMA table_info(users)") + columns = cursor.fetchall() + print(" users表结构:") + for col in columns: + print(f" {col[1]} {col[2]} {'NOT NULL' if col[3] else 'NULL'}") + + # 8. 关闭连接 + cursor.close() + conn.close() + print("\n ✓ 关闭数据库连接") + + # 清理测试文件 + if os.path.exists(db_path): + os.remove(db_path) + print(f" ✓ 清理测试文件: {db_path}") + +# 运行SQLite基础演示 +sqlite_basic_demo() +``` + +### 2.2 SQLite高级功能 + +```python +import sqlite3 +import json +from contextlib import contextmanager + +def sqlite_advanced_demo(): + """SQLite高级功能演示""" + print("=== SQLite高级功能演示 ===") + + # 1. 连接管理和上下文管理器 + print("\n1. 连接管理:") + + @contextmanager + def get_db_connection(db_path): + """数据库连接上下文管理器""" + conn = None + try: + conn = sqlite3.connect(db_path) + # 设置行工厂,使查询结果可以像字典一样访问 + conn.row_factory = sqlite3.Row + yield conn + except Exception as e: + if conn: + conn.rollback() + raise e + finally: + if conn: + conn.close() + + db_path = 'advanced_example.db' + + # 使用上下文管理器 + with get_db_connection(db_path) as conn: + cursor = conn.cursor() + + # 创建测试表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS products ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + price REAL NOT NULL, + category TEXT, + metadata TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + print(" ✓ 使用上下文管理器创建连接") + + # 2. 事务处理 + print("\n2. 事务处理:") + + def transfer_money_demo(): + """转账事务演示""" + with get_db_connection(db_path) as conn: + cursor = conn.cursor() + + # 创建账户表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS accounts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + balance REAL NOT NULL DEFAULT 0 + ) + ''') + + # 插入测试账户 + cursor.execute("INSERT OR REPLACE INTO accounts (id, name, balance) VALUES (1, '账户A', 1000)") + cursor.execute("INSERT OR REPLACE INTO accounts (id, name, balance) VALUES (2, '账户B', 500)") + conn.commit() + + try: + # 开始事务 + cursor.execute("BEGIN TRANSACTION") + + # 从账户A扣款 + cursor.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", (200, 1)) + + # 检查余额是否足够 + cursor.execute("SELECT balance FROM accounts WHERE id = ?", (1,)) + balance = cursor.fetchone()[0] + + if balance < 0: + raise ValueError("余额不足") + + # 向账户B转账 + cursor.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", (200, 2)) + + # 提交事务 + conn.commit() + print(" ✓ 转账成功") + + # 查看结果 + cursor.execute("SELECT name, balance FROM accounts") + accounts = cursor.fetchall() + for account in accounts: + print(f" {account['name']}: {account['balance']} 元") + + except Exception as e: + # 回滚事务 + conn.rollback() + print(f" ✗ 转账失败,已回滚: {e}") + + transfer_money_demo() + + # 3. 索引和性能优化 + print("\n3. 索引和性能优化:") + + with get_db_connection(db_path) as conn: + cursor = conn.cursor() + + # 创建索引 + cursor.execute("CREATE INDEX IF NOT EXISTS idx_products_category ON products(category)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_products_price ON products(price)") + print(" ✓ 创建索引") + + # 插入测试数据 + products_data = [ + ('笔记本电脑', 5999.99, '电子产品', json.dumps({'brand': 'Dell', 'model': 'XPS13'})), + ('无线鼠标', 199.99, '电子产品', json.dumps({'brand': 'Logitech', 'wireless': True})), + ('办公椅', 899.99, '家具', json.dumps({'material': '皮革', 'adjustable': True})), + ('台灯', 299.99, '家具', json.dumps({'type': 'LED', 'dimmable': True})) + ] + + cursor.executemany( + "INSERT OR REPLACE INTO products (name, price, category, metadata) VALUES (?, ?, ?, ?)", + products_data + ) + conn.commit() + print(f" ✓ 插入 {len(products_data)} 个产品") + + # 使用EXPLAIN QUERY PLAN查看查询计划 + cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM products WHERE category = '电子产品'") + plan = cursor.fetchall() + print(" 查询计划:") + for step in plan: + print(f" {step[3]}") + + # 4. JSON数据处理 + print("\n4. JSON数据处理:") + + with get_db_connection(db_path) as conn: + cursor = conn.cursor() + + # 查询并解析JSON数据 + cursor.execute("SELECT name, metadata FROM products WHERE category = '电子产品'") + products = cursor.fetchall() + + print(" 电子产品详情:") + for product in products: + metadata = json.loads(product['metadata']) + print(f" {product['name']}:") + for key, value in metadata.items(): + print(f" {key}: {value}") + + # 5. 自定义函数 + print("\n5. 自定义函数:") + + def calculate_discount(price, discount_rate): + """计算折扣价格""" + return price * (1 - discount_rate / 100) + + with get_db_connection(db_path) as conn: + # 注册自定义函数 + conn.create_function("calculate_discount", 2, calculate_discount) + + cursor = conn.cursor() + + # 使用自定义函数 + cursor.execute( + "SELECT name, price, calculate_discount(price, 20) as discounted_price FROM products" + ) + products = cursor.fetchall() + + print(" 产品价格(8折优惠):") + for product in products: + print(f" {product['name']}: {product['price']:.2f} → {product['discounted_price']:.2f}") + + # 6. 备份和恢复 + print("\n6. 数据库备份:") + + def backup_database(source_db, backup_db): + """备份数据库""" + with sqlite3.connect(source_db) as source: + with sqlite3.connect(backup_db) as backup: + source.backup(backup) + print(f" ✓ 备份完成: {source_db} → {backup_db}") + + backup_path = 'backup_example.db' + backup_database(db_path, backup_path) + + # 验证备份 + with get_db_connection(backup_path) as conn: + cursor = conn.cursor() + cursor.execute("SELECT COUNT(*) FROM products") + count = cursor.fetchone()[0] + print(f" ✓ 备份验证: 产品数量 {count}") + + # 清理文件 + import os + for file_path in [db_path, backup_path]: + if os.path.exists(file_path): + os.remove(file_path) + print(" ✓ 清理测试文件") + +# 运行SQLite高级演示 +sqlite_advanced_demo() +``` + +## 3. MySQL数据库 + +### 3.1 MySQL连接和基本操作 + +```python +# 注意:需要安装 pymysql: pip install pymysql +try: + import pymysql + PYMYSQL_AVAILABLE = True +except ImportError: + PYMYSQL_AVAILABLE = False + print("PyMySQL未安装,请运行: pip install pymysql") + +def mysql_basic_demo(): + """MySQL基础操作演示""" + print("=== MySQL基础操作演示 ===") + + if not PYMYSQL_AVAILABLE: + print(" ⚠️ PyMySQL模块未安装,跳过MySQL演示") + return + + # 1. 连接配置 + print("\n1. MySQL连接配置:") + + # 数据库连接配置 + config = { + 'host': 'localhost', + 'port': 3306, + 'user': 'root', + 'password': 'password', # 请替换为实际密码 + 'database': 'test_db', + 'charset': 'utf8mb4', + 'autocommit': False + } + + print(" 连接配置:") + for key, value in config.items(): + if key != 'password': + print(f" {key}: {value}") + else: + print(f" {key}: {'*' * len(str(value))}") + + # 2. 连接管理类 + print("\n2. MySQL连接管理:") + + class MySQLManager: + """MySQL连接管理器""" + + def __init__(self, config): + self.config = config + self.connection = None + + def connect(self): + """建立连接""" + try: + self.connection = pymysql.connect(**self.config) + print(" ✓ 连接MySQL成功") + return True + except pymysql.Error as e: + print(f" ✗ 连接失败: {e}") + return False + + def disconnect(self): + """关闭连接""" + if self.connection: + self.connection.close() + print(" ✓ 关闭MySQL连接") + + def execute_query(self, sql, params=None): + """执行查询""" + try: + with self.connection.cursor() as cursor: + cursor.execute(sql, params or ()) + return cursor.fetchall() + except pymysql.Error as e: + print(f" ✗ 查询失败: {e}") + return None + + def execute_update(self, sql, params=None): + """执行更新""" + try: + with self.connection.cursor() as cursor: + affected_rows = cursor.execute(sql, params or ()) + self.connection.commit() + return affected_rows + except pymysql.Error as e: + print(f" ✗ 更新失败: {e}") + self.connection.rollback() + return 0 + + def execute_many(self, sql, params_list): + """批量执行""" + try: + with self.connection.cursor() as cursor: + affected_rows = cursor.executemany(sql, params_list) + self.connection.commit() + return affected_rows + except pymysql.Error as e: + print(f" ✗ 批量执行失败: {e}") + self.connection.rollback() + return 0 + + # 3. 模拟MySQL操作(如果无法连接真实数据库) + print("\n3. MySQL操作演示:") + + def simulate_mysql_operations(): + """模拟MySQL操作""" + print(" 模拟MySQL数据库操作:") + + # 模拟创建表 + create_table_sql = ''' + CREATE TABLE IF NOT EXISTS employees ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + department VARCHAR(50), + salary DECIMAL(10, 2), + hire_date DATE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''' + print(" ✓ 创建员工表") + + # 模拟插入数据 + employees_data = [ + ('张三', 'zhangsan@company.com', '技术部', 8000.00, '2023-01-15'), + ('李四', 'lisi@company.com', '销售部', 6000.00, '2023-02-20'), + ('王五', 'wangwu@company.com', '人事部', 7000.00, '2023-03-10'), + ('赵六', 'zhaoliu@company.com', '技术部', 9000.00, '2023-04-05') + ] + + insert_sql = ''' + INSERT INTO employees (name, email, department, salary, hire_date) + VALUES (%s, %s, %s, %s, %s) + ''' + print(f" ✓ 插入 {len(employees_data)} 个员工") + + # 模拟查询操作 + queries = { + "查询所有员工": "SELECT * FROM employees", + "按部门查询": "SELECT * FROM employees WHERE department = '技术部'", + "薪资统计": "SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department", + "高薪员工": "SELECT name, salary FROM employees WHERE salary > 7000 ORDER BY salary DESC" + } + + for desc, sql in queries.items(): + print(f" • {desc}: {sql[:50]}...") + + # 模拟更新操作 + update_sql = "UPDATE employees SET salary = salary * 1.1 WHERE department = '技术部'" + print(" ✓ 技术部员工加薪10%") + + # 模拟删除操作 + delete_sql = "DELETE FROM employees WHERE hire_date < '2023-02-01'" + print(" ✓ 删除早期员工记录") + + # 尝试连接真实数据库,如果失败则模拟操作 + mysql_manager = MySQLManager(config) + if mysql_manager.connect(): + # 真实数据库操作 + try: + # 创建数据库(如果不存在) + mysql_manager.execute_update("CREATE DATABASE IF NOT EXISTS test_db") + mysql_manager.execute_update("USE test_db") + + # 执行实际操作... + print(" 执行真实MySQL操作") + + except Exception as e: + print(f" 操作过程中出错: {e}") + finally: + mysql_manager.disconnect() + else: + # 模拟操作 + simulate_mysql_operations() + +# 运行MySQL基础演示 +mysql_basic_demo() +``` + +### 3.2 MySQL连接池和高级功能 + +```python +# 连接池需要额外安装: pip install DBUtils +try: + from DBUtils.PooledDB import PooledDB + DBUTILS_AVAILABLE = True +except ImportError: + DBUTILS_AVAILABLE = False + +def mysql_advanced_demo(): + """MySQL高级功能演示""" + print("=== MySQL高级功能演示 ===") + + # 1. 连接池管理 + print("\n1. 连接池管理:") + + class MySQLConnectionPool: + """MySQL连接池管理器""" + + def __init__(self, config, pool_size=5): + self.config = config + self.pool_size = pool_size + self.pool = None + self._init_pool() + + def _init_pool(self): + """初始化连接池""" + if DBUTILS_AVAILABLE and PYMYSQL_AVAILABLE: + try: + self.pool = PooledDB( + creator=pymysql, + maxconnections=self.pool_size, + mincached=2, + maxcached=5, + maxshared=3, + blocking=True, + maxusage=None, + setsession=[], + ping=0, + **self.config + ) + print(f" ✓ 初始化连接池,大小: {self.pool_size}") + except Exception as e: + print(f" ✗ 连接池初始化失败: {e}") + else: + print(" ⚠️ 缺少依赖,使用模拟连接池") + self.pool = None + + def get_connection(self): + """从连接池获取连接""" + if self.pool: + return self.pool.connection() + else: + # 模拟连接 + print(" 获取模拟连接") + return None + + def execute_transaction(self, operations): + """执行事务""" + conn = self.get_connection() + if not conn: + print(" ⚠️ 无法获取连接,模拟事务执行") + return + + try: + cursor = conn.cursor() + + # 开始事务 + conn.begin() + + for operation in operations: + sql = operation['sql'] + params = operation.get('params', ()) + cursor.execute(sql, params) + + # 提交事务 + conn.commit() + print(f" ✓ 事务执行成功,包含 {len(operations)} 个操作") + + except Exception as e: + conn.rollback() + print(f" ✗ 事务执行失败,已回滚: {e}") + finally: + cursor.close() + conn.close() + + # 2. 数据访问对象 (DAO) 模式 + print("\n2. 数据访问对象模式:") + + class UserDAO: + """用户数据访问对象""" + + def __init__(self, connection_pool): + self.pool = connection_pool + + def create_user(self, username, email, password): + """创建用户""" + sql = "INSERT INTO users (username, email, password) VALUES (%s, %s, %s)" + params = (username, email, password) + + # 模拟执行 + print(f" ✓ 创建用户: {username} ({email})") + return True + + def get_user_by_id(self, user_id): + """根据ID获取用户""" + sql = "SELECT * FROM users WHERE id = %s" + params = (user_id,) + + # 模拟返回数据 + user_data = { + 'id': user_id, + 'username': f'user_{user_id}', + 'email': f'user_{user_id}@example.com', + 'created_at': '2023-01-01 00:00:00' + } + + print(f" ✓ 获取用户: {user_data['username']}") + return user_data + + def update_user(self, user_id, **kwargs): + """更新用户信息""" + if not kwargs: + return False + + set_clause = ', '.join([f"{key} = %s" for key in kwargs.keys()]) + sql = f"UPDATE users SET {set_clause} WHERE id = %s" + params = list(kwargs.values()) + [user_id] + + print(f" ✓ 更新用户 {user_id}: {list(kwargs.keys())}") + return True + + def delete_user(self, user_id): + """删除用户""" + sql = "DELETE FROM users WHERE id = %s" + params = (user_id,) + + print(f" ✓ 删除用户: {user_id}") + return True + + def search_users(self, keyword, limit=10): + """搜索用户""" + sql = "SELECT * FROM users WHERE username LIKE %s OR email LIKE %s LIMIT %s" + params = (f'%{keyword}%', f'%{keyword}%', limit) + + # 模拟搜索结果 + results = [ + {'id': i, 'username': f'{keyword}_user_{i}', 'email': f'{keyword}_{i}@example.com'} + for i in range(1, min(limit + 1, 4)) + ] + + print(f" ✓ 搜索用户 '{keyword}': 找到 {len(results)} 个结果") + return results + + # 3. 测试连接池和DAO + print("\n3. 测试连接池和DAO:") + + # 创建连接池 + config = { + 'host': 'localhost', + 'user': 'root', + 'password': 'password', + 'database': 'test_db', + 'charset': 'utf8mb4' + } + + pool = MySQLConnectionPool(config, pool_size=10) + + # 创建DAO实例 + user_dao = UserDAO(pool) + + # 测试CRUD操作 + print("\n CRUD操作测试:") + + # 创建用户 + user_dao.create_user('张三', 'zhangsan@example.com', 'password123') + user_dao.create_user('李四', 'lisi@example.com', 'password456') + + # 查询用户 + user = user_dao.get_user_by_id(1) + + # 更新用户 + user_dao.update_user(1, email='zhangsan_new@example.com', username='张三_new') + + # 搜索用户 + results = user_dao.search_users('张') + + # 删除用户 + user_dao.delete_user(2) + + # 4. 批量操作和性能优化 + print("\n4. 批量操作和性能优化:") + + def batch_operations_demo(): + """批量操作演示""" + + # 批量插入 + batch_data = [ + ('用户1', 'user1@example.com', 'pass1'), + ('用户2', 'user2@example.com', 'pass2'), + ('用户3', 'user3@example.com', 'pass3'), + ('用户4', 'user4@example.com', 'pass4'), + ('用户5', 'user5@example.com', 'pass5') + ] + + print(f" ✓ 批量插入 {len(batch_data)} 个用户") + + # 分页查询 + page_size = 10 + page_num = 1 + offset = (page_num - 1) * page_size + + pagination_sql = f"SELECT * FROM users LIMIT {page_size} OFFSET {offset}" + print(f" ✓ 分页查询: 第{page_num}页,每页{page_size}条") + + # 索引优化建议 + index_suggestions = [ + "CREATE INDEX idx_users_email ON users(email)", + "CREATE INDEX idx_users_username ON users(username)", + "CREATE INDEX idx_users_created_at ON users(created_at)" + ] + + print(" 索引优化建议:") + for suggestion in index_suggestions: + print(f" {suggestion}") + + batch_operations_demo() + + # 5. 数据库监控和统计 + print("\n5. 数据库监控:") + + def database_monitoring_demo(): + """数据库监控演示""" + + monitoring_queries = { + "连接数统计": "SHOW STATUS LIKE 'Threads_connected'", + "查询缓存命中率": "SHOW STATUS LIKE 'Qcache_hits'", + "慢查询数量": "SHOW STATUS LIKE 'Slow_queries'", + "表锁等待": "SHOW STATUS LIKE 'Table_locks_waited'", + "InnoDB缓冲池": "SHOW STATUS LIKE 'Innodb_buffer_pool_read_requests'" + } + + print(" 监控查询:") + for desc, query in monitoring_queries.items(): + print(f" {desc}: {query}") + + # 性能分析 + performance_tips = [ + "使用EXPLAIN分析查询计划", + "合理创建索引,避免过多索引", + "使用连接池减少连接开销", + "定期分析表统计信息", + "监控慢查询日志", + "优化数据库配置参数" + ] + + print("\n 性能优化建议:") + for tip in performance_tips: + print(f" • {tip}") + + database_monitoring_demo() + +# 运行MySQL高级演示 +mysql_advanced_demo() +``` + +## 4. ORM框架 + +### 4.1 SQLAlchemy基础 + +```python +# 注意:需要安装 SQLAlchemy: pip install sqlalchemy +try: + from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey, Text + from sqlalchemy.ext.declarative import declarative_base + from sqlalchemy.orm import sessionmaker, relationship + from datetime import datetime + SQLALCHEMY_AVAILABLE = True +except ImportError: + SQLALCHEMY_AVAILABLE = False + print("SQLAlchemy未安装,请运行: pip install sqlalchemy") + +def sqlalchemy_basic_demo(): + """SQLAlchemy基础演示""" + print("=== SQLAlchemy基础演示 ===") + + if not SQLALCHEMY_AVAILABLE: + print(" ⚠️ SQLAlchemy模块未安装,跳过ORM演示") + return + + # 1. 创建数据库引擎 + print("\n1. 创建数据库引擎:") + + # 使用SQLite内存数据库进行演示 + engine = create_engine('sqlite:///:memory:', echo=False) + print(" ✓ 创建SQLite内存数据库引擎") + + # 2. 定义模型 + print("\n2. 定义ORM模型:") + + Base = declarative_base() + + class User(Base): + """用户模型""" + __tablename__ = 'users' + + id = Column(Integer, primary_key=True) + username = Column(String(50), unique=True, nullable=False) + email = Column(String(100), unique=True, nullable=False) + created_at = Column(DateTime, default=datetime.utcnow) + + # 关系 + posts = relationship("Post", back_populates="author") + + def __repr__(self): + return f"当前用户: {{ session.get('username', '未登录') }}
+ +{% if messages %} + {% for message in messages %} +", "
") +markdown_formatter = create_formatter("**", "**") + +print(html_formatter("Hello")) #Hello
+print(markdown_formatter("Bold")) # **Bold** +``` + +### 2.3 函数组合 + +```python +def compose(f, g): + """函数组合:返回 f(g(x))""" + return lambda x: f(g(x)) + +def pipe(*functions): + """管道操作:从左到右依次应用函数""" + def piped_function(value): + for func in functions: + value = func(value) + return value + return piped_function + +# 基础函数 +def add_one(x): + return x + 1 + +def multiply_by_two(x): + return x * 2 + +def square(x): + return x ** 2 + +# 函数组合 +add_then_multiply = compose(multiply_by_two, add_one) +result1 = add_then_multiply(3) # multiply_by_two(add_one(3)) = multiply_by_two(4) = 8 +print(f"组合结果:{result1}") + +# 管道操作 +process_number = pipe(add_one, multiply_by_two, square) +result2 = process_number(3) # ((3+1)*2)^2 = (4*2)^2 = 8^2 = 64 +print(f"管道结果:{result2}") + +# 处理字符串的管道 +def to_upper(s): + return s.upper() + +def add_exclamation(s): + return s + "!" + +def add_prefix(s): + return ">>> " + s + +process_text = pipe(to_upper, add_exclamation, add_prefix) +result3 = process_text("hello world") +print(f"文本处理:{result3}") # >>> HELLO WORLD! +``` + +--- + +## 三、内置高阶函数深入 + +### 3.1 map()函数进阶 + +```python +# 处理多个序列 +def add_three_numbers(x, y, z): + return x + y + z + +list1 = [1, 2, 3] +list2 = [10, 20, 30] +list3 = [100, 200, 300] + +result = list(map(add_three_numbers, list1, list2, list3)) +print(f"三个列表相加:{result}") # [111, 222, 333] + +# 处理字典 +students = [ + {'name': 'Alice', 'score': 85}, + {'name': 'Bob', 'score': 92}, + {'name': 'Charlie', 'score': 78} +] + +# 提取姓名 +names = list(map(lambda student: student['name'], students)) +print(f"学生姓名:{names}") # ['Alice', 'Bob', 'Charlie'] + +# 计算等级 +def get_grade(score): + if score >= 90: + return 'A' + elif score >= 80: + return 'B' + elif score >= 70: + return 'C' + else: + return 'D' + +grades = list(map(lambda s: get_grade(s['score']), students)) +print(f"学生等级:{grades}") # ['B', 'A', 'C'] +``` + +### 3.2 filter()函数进阶 + +```python +# 复杂过滤条件 +numbers = range(1, 21) + +# 过滤质数 +def is_prime(n): + if n < 2: + return False + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + return False + return True + +primes = list(filter(is_prime, numbers)) +print(f"质数:{primes}") # [2, 3, 5, 7, 11, 13, 17, 19] + +# 过滤字符串 +words = ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig'] + +# 长度大于5且包含'e'的单词 +filtered_words = list(filter( + lambda word: len(word) > 5 and 'e' in word, + words +)) +print(f"过滤后的单词:{filtered_words}") # ['cherry', 'elderberry'] + +# 过滤学生数据 +students = [ + {'name': 'Alice', 'age': 20, 'score': 85}, + {'name': 'Bob', 'age': 22, 'score': 92}, + {'name': 'Charlie', 'age': 19, 'score': 78}, + {'name': 'Diana', 'age': 21, 'score': 96} +] + +# 年龄大于20且分数大于80的学生 +excellent_students = list(filter( + lambda s: s['age'] > 20 and s['score'] > 80, + students +)) +print("优秀学生:") +for student in excellent_students: + print(f" {student['name']}: {student['age']}岁, {student['score']}分") +``` + +### 3.3 reduce()函数进阶 + +```python +from functools import reduce + +# 复杂的累积操作 +numbers = [1, 2, 3, 4, 5] + +# 计算阶乘 +factorial = reduce(lambda x, y: x * y, numbers) +print(f"阶乘:{factorial}") # 120 + +# 找到最大值和最小值 +max_value = reduce(lambda x, y: x if x > y else y, numbers) +min_value = reduce(lambda x, y: x if x < y else y, numbers) +print(f"最大值:{max_value}, 最小值:{min_value}") # 5, 1 + +# 字符串操作 +words = ['Python', 'is', 'awesome', 'for', 'programming'] + +# 连接字符串 +sentence = reduce(lambda x, y: x + ' ' + y, words) +print(f"句子:{sentence}") # Python is awesome for programming + +# 找最长的单词 +longest_word = reduce( + lambda x, y: x if len(x) > len(y) else y, + words +) +print(f"最长单词:{longest_word}") # programming + +# 复杂数据结构的处理 +orders = [ + {'id': 1, 'amount': 100}, + {'id': 2, 'amount': 250}, + {'id': 3, 'amount': 75}, + {'id': 4, 'amount': 300} +] + +# 计算总金额 +total_amount = reduce( + lambda total, order: total + order['amount'], + orders, + 0 # 初始值 +) +print(f"总金额:{total_amount}") # 725 + +# 合并字典 +data_sources = [ + {'users': 100, 'posts': 500}, + {'users': 50, 'comments': 200}, + {'users': 75, 'likes': 1000} +] + +merged_data = reduce( + lambda acc, data: {**acc, **data}, + data_sources, + {} +) +print(f"合并数据:{merged_data}") +# {'users': 75, 'posts': 500, 'comments': 200, 'likes': 1000} +``` + +--- + +## 四、函数式编程工具 + +### 4.1 itertools模块 + +```python +import itertools + +# itertools.chain - 连接多个可迭代对象 +list1 = [1, 2, 3] +list2 = [4, 5, 6] +list3 = [7, 8, 9] + +chained = list(itertools.chain(list1, list2, list3)) +print(f"连接列表:{chained}") # [1, 2, 3, 4, 5, 6, 7, 8, 9] + +# itertools.cycle - 无限循环 +cycler = itertools.cycle(['A', 'B', 'C']) +first_10 = [next(cycler) for _ in range(10)] +print(f"循环前10个:{first_10}") # ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A'] + +# itertools.repeat - 重复元素 +repeated = list(itertools.repeat('Hello', 5)) +print(f"重复元素:{repeated}") # ['Hello', 'Hello', 'Hello', 'Hello', 'Hello'] + +# itertools.takewhile - 条件为真时取元素 +numbers = [1, 3, 5, 8, 9, 11, 13] +less_than_10 = list(itertools.takewhile(lambda x: x < 10, numbers)) +print(f"小于10的连续元素:{less_than_10}") # [1, 3, 5, 8, 9] + +# itertools.dropwhile - 条件为真时跳过元素 +after_10 = list(itertools.dropwhile(lambda x: x < 10, numbers)) +print(f"大于等于10的元素:{after_10}") # [11, 13] + +# itertools.groupby - 分组 +data = [('A', 1), ('A', 2), ('B', 3), ('B', 4), ('C', 5)] +grouped = {k: list(g) for k, g in itertools.groupby(data, key=lambda x: x[0])} +print(f"分组数据:{grouped}") +# {'A': [('A', 1), ('A', 2)], 'B': [('B', 3), ('B', 4)], 'C': [('C', 5)]} +``` + +### 4.2 operator模块 + +```python +import operator +from functools import reduce + +# 使用operator模块替代lambda +numbers = [1, 2, 3, 4, 5] + +# 求和 +total = reduce(operator.add, numbers) +print(f"总和:{total}") # 15 + +# 求积 +product = reduce(operator.mul, numbers) +print(f"乘积:{product}") # 120 + +# 字符串连接 +words = ['Hello', 'World', 'Python'] +sentence = reduce(operator.add, words) +print(f"连接字符串:{sentence}") # HelloWorldPython + +# 获取属性和索引 +class Person: + def __init__(self, name, age): + self.name = name + self.age = age + + def __repr__(self): + return f"Person('{self.name}', {self.age})" + +people = [ + Person('Alice', 25), + Person('Bob', 30), + Person('Charlie', 20) +] + +# 按年龄排序 +sorted_by_age = sorted(people, key=operator.attrgetter('age')) +print(f"按年龄排序:{sorted_by_age}") + +# 按姓名排序 +sorted_by_name = sorted(people, key=operator.attrgetter('name')) +print(f"按姓名排序:{sorted_by_name}") + +# 处理元组列表 +student_scores = [('Alice', 85), ('Bob', 92), ('Charlie', 78)] +sorted_by_score = sorted(student_scores, key=operator.itemgetter(1)) +print(f"按分数排序:{sorted_by_score}") +``` + +### 4.3 functools模块进阶 + +```python +from functools import partial, wraps, lru_cache, singledispatch + +# partial - 偏函数应用 +def multiply(x, y, z): + return x * y * z + +# 创建偏函数 +double = partial(multiply, 2) # 固定第一个参数为2 +triple = partial(multiply, 3) # 固定第一个参数为3 + +print(double(5, 6)) # 2 * 5 * 6 = 60 +print(triple(4, 5)) # 3 * 4 * 5 = 60 + +# 更复杂的偏函数 +def log_message(level, message, timestamp=None): + import datetime + if timestamp is None: + timestamp = datetime.datetime.now() + return f"[{timestamp}] {level}: {message}" + +# 创建特定级别的日志函数 +info_log = partial(log_message, "INFO") +error_log = partial(log_message, "ERROR") +warning_log = partial(log_message, "WARNING") + +print(info_log("应用启动")) +print(error_log("数据库连接失败")) +print(warning_log("内存使用率过高")) + +# lru_cache - 缓存装饰器 +@lru_cache(maxsize=128) +def fibonacci(n): + """带缓存的斐波那契函数""" + if n < 2: + return n + return fibonacci(n-1) + fibonacci(n-2) + +# 测试缓存效果 +import time + +start = time.time() +result = fibonacci(35) +end = time.time() +print(f"fibonacci(35) = {result}, 耗时: {end - start:.4f}秒") + +# 第二次调用会很快(使用缓存) +start = time.time() +result = fibonacci(35) +end = time.time() +print(f"fibonacci(35) = {result}, 耗时: {end - start:.6f}秒") + +# singledispatch - 单分派泛型函数 +@singledispatch +def process_data(data): + """默认处理函数""" + return f"处理未知类型: {type(data).__name__}" + +@process_data.register +def _(data: int): + return f"处理整数: {data * 2}" + +@process_data.register +def _(data: str): + return f"处理字符串: {data.upper()}" + +@process_data.register +def _(data: list): + return f"处理列表: {len(data)} 个元素" + +# 测试单分派 +print(process_data(42)) # 处理整数: 84 +print(process_data("hello")) # 处理字符串: HELLO +print(process_data([1,2,3])) # 处理列表: 3 个元素 +print(process_data(3.14)) # 处理未知类型: float +``` + +--- + +## 五、不可变数据结构 + +### 5.1 使用元组和命名元组 + +```python +from collections import namedtuple + +# 普通元组 +point = (3, 4) +print(f"点坐标:{point}") +print(f"x坐标:{point[0]}, y坐标:{point[1]}") + +# 命名元组 - 更具可读性 +Point = namedtuple('Point', ['x', 'y']) +point = Point(3, 4) +print(f"点坐标:{point}") +print(f"x坐标:{point.x}, y坐标:{point.y}") + +# 命名元组的方法 +print(f"转为字典:{point._asdict()}") +print(f"替换值:{point._replace(x=5)}") + +# 复杂的命名元组 +Student = namedtuple('Student', ['name', 'age', 'grade', 'scores']) +student = Student( + name='Alice', + age=20, + grade='A', + scores=(85, 92, 78, 96) +) + +print(f"学生信息:{student}") +print(f"平均分:{sum(student.scores) / len(student.scores):.2f}") + +# 函数式处理命名元组 +def calculate_gpa(student): + """计算GPA(纯函数)""" + average = sum(student.scores) / len(student.scores) + if average >= 90: + return 4.0 + elif average >= 80: + return 3.0 + elif average >= 70: + return 2.0 + else: + return 1.0 + +def update_grade(student, new_grade): + """更新等级(返回新对象)""" + return student._replace(grade=new_grade) + +gpa = calculate_gpa(student) +print(f"GPA:{gpa}") + +updated_student = update_grade(student, 'A+') +print(f"更新后的学生:{updated_student}") +print(f"原学生不变:{student}") +``` + +### 5.2 frozenset的使用 + +```python +# frozenset - 不可变集合 +mutable_set = {1, 2, 3, 4, 5} +immutable_set = frozenset([1, 2, 3, 4, 5]) + +print(f"可变集合:{mutable_set}") +print(f"不可变集合:{immutable_set}") + +# frozenset可以作为字典的键 +set_dict = { + frozenset([1, 2]): "小集合", + frozenset([1, 2, 3, 4, 5]): "大集合" +} + +print(f"集合字典:{set_dict}") + +# 函数式操作frozenset +def union_sets(*sets): + """合并多个集合""" + result = frozenset() + for s in sets: + result = result.union(s) + return result + +def filter_set(s, predicate): + """过滤集合元素""" + return frozenset(filter(predicate, s)) + +set1 = frozenset([1, 2, 3]) +set2 = frozenset([3, 4, 5]) +set3 = frozenset([5, 6, 7]) + +unioned = union_sets(set1, set2, set3) +print(f"合并集合:{uniond}") + +even_numbers = filter_set(uniond, lambda x: x % 2 == 0) +print(f"偶数:{even_numbers}") +``` + +--- + +## 六、函数式编程实战 + +### 6.1 数据处理管道 + +```python +from functools import reduce +from typing import List, Dict, Any + +# 学生数据 +students_data = [ + {'name': 'Alice', 'age': 20, 'scores': [85, 92, 78, 96], 'major': 'CS'}, + {'name': 'Bob', 'age': 22, 'scores': [76, 88, 82, 79], 'major': 'Math'}, + {'name': 'Charlie', 'age': 19, 'scores': [95, 87, 91, 93], 'major': 'CS'}, + {'name': 'Diana', 'age': 21, 'scores': [68, 74, 82, 79], 'major': 'Physics'}, + {'name': 'Eve', 'age': 20, 'scores': [89, 94, 87, 92], 'major': 'CS'} +] + +# 纯函数定义 +def calculate_average(scores: List[int]) -> float: + """计算平均分""" + return sum(scores) / len(scores) + +def add_average_score(student: Dict[str, Any]) -> Dict[str, Any]: + """添加平均分字段""" + return { + **student, + 'average': calculate_average(student['scores']) + } + +def is_excellent_student(student: Dict[str, Any]) -> bool: + """判断是否为优秀学生(平均分>85)""" + return student['average'] > 85 + +def is_cs_major(student: Dict[str, Any]) -> bool: + """判断是否为CS专业""" + return student['major'] == 'CS' + +def get_student_summary(student: Dict[str, Any]) -> Dict[str, Any]: + """获取学生摘要信息""" + return { + 'name': student['name'], + 'average': round(student['average'], 2), + 'major': student['major'] + } + +# 函数式数据处理管道 +def process_students(students: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + """处理学生数据的完整管道""" + return list( + map( + get_student_summary, + filter( + lambda s: is_excellent_student(s) and is_cs_major(s), + map(add_average_score, students) + ) + ) + ) + +# 执行处理 +excellent_cs_students = process_students(students_data) +print("优秀的CS专业学生:") +for student in excellent_cs_students: + print(f" {student['name']}: {student['average']} ({student['major']})") + +# 使用reduce计算统计信息 +def calculate_stats(students: List[Dict[str, Any]]) -> Dict[str, float]: + """计算统计信息""" + students_with_avg = list(map(add_average_score, students)) + + total_avg = reduce( + lambda acc, student: acc + student['average'], + students_with_avg, + 0 + ) / len(students_with_avg) + + max_avg = reduce( + lambda acc, student: max(acc, student['average']), + students_with_avg, + 0 + ) + + min_avg = reduce( + lambda acc, student: min(acc, student['average']), + students_with_avg, + float('inf') + ) + + return { + 'total_average': round(total_avg, 2), + 'max_average': round(max_avg, 2), + 'min_average': round(min_avg, 2) + } + +stats = calculate_stats(students_data) +print(f"\n统计信息:{stats}") +``` + +### 6.2 函数式配置管理 + +```python +from functools import partial +from typing import Callable, Any + +# 配置验证函数 +def validate_range(min_val: float, max_val: float, value: float) -> bool: + """验证值是否在范围内""" + return min_val <= value <= max_val + +def validate_type(expected_type: type, value: Any) -> bool: + """验证类型""" + return isinstance(value, expected_type) + +def validate_length(min_len: int, max_len: int, value: str) -> bool: + """验证字符串长度""" + return min_len <= len(value) <= max_len + +# 创建特定的验证器 +validate_port = partial(validate_range, 1, 65535) +validate_percentage = partial(validate_range, 0, 100) +validate_string = partial(validate_type, str) +validate_int = partial(validate_type, int) +validate_username = partial(validate_length, 3, 20) + +# 配置规则 +config_rules = { + 'server_port': [validate_int, validate_port], + 'cpu_threshold': [validate_int, validate_percentage], + 'username': [validate_string, validate_username], + 'timeout': [validate_int, partial(validate_range, 1, 300)] +} + +def validate_config(rules: Dict[str, List[Callable]], config: Dict[str, Any]) -> Dict[str, bool]: + """验证配置""" + results = {} + + for key, validators in rules.items(): + if key in config: + # 所有验证器都必须通过 + results[key] = all( + validator(config[key]) for validator in validators + ) + else: + results[key] = False + + return results + +# 测试配置 +test_config = { + 'server_port': 8080, + 'cpu_threshold': 85, + 'username': 'alice', + 'timeout': 30 +} + +validation_results = validate_config(config_rules, test_config) +print("配置验证结果:") +for key, is_valid in validation_results.items(): + status = "✓" if is_valid else "✗" + print(f" {key}: {status}") + +# 无效配置测试 +invalid_config = { + 'server_port': 70000, # 超出范围 + 'cpu_threshold': 150, # 超出百分比范围 + 'username': 'ab', # 太短 + 'timeout': 500 # 超时时间太长 +} + +invalid_results = validate_config(config_rules, invalid_config) +print("\n无效配置验证结果:") +for key, is_valid in invalid_results.items(): + status = "✓" if is_valid else "✗" + print(f" {key}: {status}") +``` + +### 6.3 函数式错误处理 + +```python +from typing import Union, Callable, Any +from dataclasses import dataclass + +# 定义Result类型(模拟Rust的Result) +@dataclass +class Success: + value: Any + + def is_success(self) -> bool: + return True + + def is_error(self) -> bool: + return False + + def map(self, func: Callable) -> 'Union[Success, Error]': + try: + return Success(func(self.value)) + except Exception as e: + return Error(str(e)) + + def flat_map(self, func: Callable) -> 'Union[Success, Error]': + try: + return func(self.value) + except Exception as e: + return Error(str(e)) + +@dataclass +class Error: + message: str + + def is_success(self) -> bool: + return False + + def is_error(self) -> bool: + return True + + def map(self, func: Callable) -> 'Error': + return self + + def flat_map(self, func: Callable) -> 'Error': + return self + +Result = Union[Success, Error] + +# 安全的数学操作 +def safe_divide(x: float, y: float) -> Result: + """安全除法""" + if y == 0: + return Error("除零错误") + return Success(x / y) + +def safe_sqrt(x: float) -> Result: + """安全开方""" + if x < 0: + return Error("负数不能开方") + return Success(x ** 0.5) + +def safe_log(x: float) -> Result: + """安全对数""" + if x <= 0: + return Error("对数的参数必须大于0") + import math + return Success(math.log(x)) + +# 函数式错误处理链 +def calculate_complex_formula(a: float, b: float, c: float) -> Result: + """计算复杂公式:log(sqrt(a/b) + c)""" + return (safe_divide(a, b) + .flat_map(lambda x: safe_sqrt(x)) + .map(lambda x: x + c) + .flat_map(lambda x: safe_log(x))) + +# 测试错误处理 +test_cases = [ + (16, 4, 1), # 正常情况 + (16, 0, 1), # 除零错误 + (-16, 4, 1), # 负数开方错误 + (16, 4, -3), # 对数参数错误 +] + +print("复杂公式计算结果:") +for a, b, c in test_cases: + result = calculate_complex_formula(a, b, c) + if result.is_success(): + print(f" f({a}, {b}, {c}) = {result.value:.4f}") + else: + print(f" f({a}, {b}, {c}) = 错误: {result.message}") + +# 批量处理 +def process_batch(data: List[tuple], processor: Callable) -> Dict[str, List]: + """批量处理数据""" + successes = [] + errors = [] + + for item in data: + result = processor(*item) + if result.is_success(): + successes.append((item, result.value)) + else: + errors.append((item, result.message)) + + return {'successes': successes, 'errors': errors} + +batch_results = process_batch(test_cases, calculate_complex_formula) +print(f"\n批量处理结果:") +print(f"成功: {len(batch_results['successes'])} 个") +print(f"失败: {len(batch_results['errors'])} 个") +``` + +--- + +## 七、总结 + +### 7.1 函数式编程的优势 + +1. **可预测性**:纯函数使代码行为可预测 +2. **可测试性**:纯函数易于单元测试 +3. **可组合性**:函数可以轻松组合成复杂操作 +4. **并发安全**:不可变数据避免了并发问题 +5. **代码简洁**:高阶函数减少重复代码 + +### 7.2 何时使用函数式编程 + +**适合的场景:** +- 数据转换和处理 +- 配置验证 +- 数学计算 +- 并发编程 +- 需要高可靠性的系统 + +**不太适合的场景:** +- 需要频繁修改状态的应用 +- 性能要求极高的场景 +- 简单的脚本任务 + +### 7.3 最佳实践 + +1. **优先使用纯函数**:避免副作用 +2. **保持函数简单**:一个函数只做一件事 +3. **使用类型注解**:提高代码可读性 +4. **合理使用高阶函数**:不要过度抽象 +5. **结合其他范式**:Python支持多种编程范式 + +### 7.4 下一步学习 + +- **深入学习itertools和functools** +- **了解更多函数式编程库**(如toolz) +- **学习其他函数式语言**(如Haskell、Clojure) +- **实践函数式设计模式** + +恭喜你!掌握了函数式编程,你的Python技能又上了一个新台阶!🎉 + +--- + +**练习建议:** +1. 重构现有代码,使用纯函数 +2. 练习使用map、filter、reduce处理数据 +3. 尝试函数组合和管道操作 +4. 实现自己的高阶函数 +5. 用函数式方法解决实际问题 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Python/8.md b/docs/Python/8.md new file mode 100644 index 000000000..3bede030c --- /dev/null +++ b/docs/Python/8.md @@ -0,0 +1,1553 @@ +--- +title: 第8天-模块 +author: 哪吒 +date: '2023-06-15' +--- + +# 第8天-Python模块与包 + +欢迎来到Python模块的世界!模块是Python代码组织和重用的基础,掌握模块系统将让你的代码更加模块化、可维护和可扩展。 + +## 什么是模块? + +模块(Module)是包含Python代码的文件,通常以`.py`为扩展名。模块可以包含函数、类、变量以及可执行的代码。 + +> **生活类比**: +> - **模块**:像工具箱中的不同工具,每个工具有特定的功能 +> - **包**:像工具箱本身,将相关的工具组织在一起 +> - **导入**:像从工具箱中取出需要的工具来使用 + +### 模块的优势 + +1. **代码重用**:避免重复编写相同的代码 +2. **命名空间**:避免变量名冲突 +3. **代码组织**:将相关功能组织在一起 +4. **维护性**:便于代码的维护和更新 +5. **协作开发**:团队成员可以独立开发不同模块 + +--- + +## 一、创建和使用模块 + +### 1.1 创建简单模块 + +让我们创建一个数学工具模块: + +```python +# 文件名:math_utils.py +"""数学工具模块 + +这个模块提供了一些常用的数学函数。 +""" + +import math + +# 模块级变量 +PI = 3.14159265359 +E = 2.71828182846 + +def add(x, y): + """加法函数""" + return x + y + +def subtract(x, y): + """减法函数""" + return x - y + +def multiply(x, y): + """乘法函数""" + return x * y + +def divide(x, y): + """除法函数""" + if y == 0: + raise ValueError("除数不能为零") + return x / y + +def power(base, exponent): + """幂运算""" + return base ** exponent + +def factorial(n): + """计算阶乘""" + if n < 0: + raise ValueError("阶乘的参数必须是非负整数") + if n == 0 or n == 1: + return 1 + return n * factorial(n - 1) + +def is_prime(n): + """判断是否为质数""" + if n < 2: + return False + for i in range(2, int(math.sqrt(n)) + 1): + if n % i == 0: + return False + return True + +def gcd(a, b): + """计算最大公约数""" + while b: + a, b = b, a % b + return a + +def lcm(a, b): + """计算最小公倍数""" + return abs(a * b) // gcd(a, b) + +class Calculator: + """简单计算器类""" + + def __init__(self): + self.history = [] + + def calculate(self, operation, x, y=None): + """执行计算并记录历史""" + if operation == 'add' and y is not None: + result = add(x, y) + elif operation == 'subtract' and y is not None: + result = subtract(x, y) + elif operation == 'multiply' and y is not None: + result = multiply(x, y) + elif operation == 'divide' and y is not None: + result = divide(x, y) + elif operation == 'factorial': + result = factorial(x) + else: + raise ValueError("不支持的操作") + + self.history.append(f"{operation}({x}, {y}) = {result}" if y is not None else f"{operation}({x}) = {result}") + return result + + def get_history(self): + """获取计算历史""" + return self.history.copy() + + def clear_history(self): + """清空计算历史""" + self.history.clear() + +# 模块级代码(导入时执行) +print(f"数学工具模块已加载,π = {PI}, e = {E}") + +# 测试代码(只在直接运行时执行) +if __name__ == "__main__": + print("测试数学工具模块:") + print(f"5 + 3 = {add(5, 3)}") + print(f"10 - 4 = {subtract(10, 4)}") + print(f"6 * 7 = {multiply(6, 7)}") + print(f"15 / 3 = {divide(15, 3)}") + print(f"2^8 = {power(2, 8)}") + print(f"5! = {factorial(5)}") + print(f"17是质数吗?{is_prime(17)}") + print(f"gcd(48, 18) = {gcd(48, 18)}") + print(f"lcm(12, 8) = {lcm(12, 8)}") + + calc = Calculator() + calc.calculate('add', 10, 5) + calc.calculate('factorial', 5) + print("计算历史:", calc.get_history()) +``` + +### 1.2 导入和使用模块 + +```python +# 使用我们创建的math_utils模块 + +# 方法1:导入整个模块 +import math_utils + +result1 = math_utils.add(10, 5) +print(f"10 + 5 = {result1}") +print(f"π的值:{math_utils.PI}") + +# 方法2:导入特定函数 +from math_utils import multiply, divide, factorial + +result2 = multiply(6, 7) +result3 = divide(20, 4) +result4 = factorial(5) +print(f"6 * 7 = {result2}") +print(f"20 / 4 = {result3}") +print(f"5! = {result4}") + +# 方法3:导入并重命名 +from math_utils import is_prime as check_prime +from math_utils import Calculator as Calc + +print(f"13是质数吗?{check_prime(13)}") +calc = Calc() +result5 = calc.calculate('add', 15, 25) +print(f"计算结果:{result5}") + +# 方法4:导入所有(不推荐) +# from math_utils import * +# 这种方式可能导致命名冲突,一般不推荐使用 + +# 方法5:使用别名导入模块 +import math_utils as mu + +result6 = mu.power(2, 10) +print(f"2^10 = {result6}") +``` + +--- + +## 二、模块搜索路径 + +### 2.1 Python如何查找模块 + +Python按以下顺序搜索模块: + +1. **当前目录** +2. **PYTHONPATH环境变量指定的目录** +3. **标准库目录** +4. **site-packages目录**(第三方包) + +```python +import sys + +# 查看模块搜索路径 +print("Python模块搜索路径:") +for i, path in enumerate(sys.path, 1): + print(f"{i}. {path}") + +# 动态添加搜索路径 +sys.path.append('/path/to/your/modules') + +# 查看已加载的模块 +print("\n已加载的模块:") +for module_name in sorted(sys.modules.keys())[:10]: # 只显示前10个 + print(f"- {module_name}") +``` + +### 2.2 模块的属性和信息 + +```python +import math_utils +import math + +# 查看模块属性 +print("math_utils模块的属性:") +for attr in dir(math_utils): + if not attr.startswith('_'): # 不显示私有属性 + print(f"- {attr}") + +# 模块的特殊属性 +print(f"\n模块名称:{math_utils.__name__}") +print(f"模块文档:{math_utils.__doc__}") +print(f"模块文件路径:{math_utils.__file__}") + +# 获取函数的帮助信息 +help(math_utils.factorial) + +# 检查对象类型 +print(f"\nadd是函数吗?{callable(math_utils.add)}") +print(f"PI是什么类型?{type(math_utils.PI)}") +print(f"Calculator是类吗?{isinstance(math_utils.Calculator, type)}") +``` + +--- + +## 三、包(Packages) + +### 3.1 什么是包 + +包是包含多个模块的目录,必须包含一个`__init__.py`文件(可以为空)。 + +``` +my_package/ + __init__.py + module1.py + module2.py + subpackage/ + __init__.py + module3.py + module4.py +``` + +### 3.2 创建包结构 + +让我们创建一个完整的工具包: + +```python +# 目录结构: +# utils/ +# __init__.py +# string_utils.py +# file_utils.py +# data_utils.py +# math/ +# __init__.py +# basic.py +# advanced.py + +# utils/__init__.py +"""工具包 + +这个包提供了各种实用工具函数。 +""" + +__version__ = "1.0.0" +__author__ = "哪吒" + +# 导入子模块,使其可以直接从包中访问 +from .string_utils import * +from .file_utils import read_file, write_file +from .data_utils import DataProcessor + +# 定义包级别的函数 +def get_package_info(): + """获取包信息""" + return { + 'name': __name__, + 'version': __version__, + 'author': __author__ + } + +# 定义__all__来控制from utils import *的行为 +__all__ = [ + 'get_package_info', + 'capitalize_words', + 'reverse_string', + 'read_file', + 'write_file', + 'DataProcessor' +] +``` + +```python +# utils/string_utils.py +"""字符串工具模块""" + +def capitalize_words(text): + """将每个单词的首字母大写""" + return ' '.join(word.capitalize() for word in text.split()) + +def reverse_string(text): + """反转字符串""" + return text[::-1] + +def count_words(text): + """统计单词数量""" + return len(text.split()) + +def remove_duplicates(text): + """移除重复的单词""" + words = text.split() + unique_words = [] + for word in words: + if word not in unique_words: + unique_words.append(word) + return ' '.join(unique_words) + +def is_palindrome(text): + """检查是否为回文""" + cleaned = ''.join(char.lower() for char in text if char.isalnum()) + return cleaned == cleaned[::-1] + +class StringProcessor: + """字符串处理器类""" + + def __init__(self, text): + self.text = text + + def process(self, operations): + """应用一系列操作""" + result = self.text + for operation in operations: + if operation == 'capitalize': + result = capitalize_words(result) + elif operation == 'reverse': + result = reverse_string(result) + elif operation == 'remove_duplicates': + result = remove_duplicates(result) + return result +``` + +```python +# utils/file_utils.py +"""文件操作工具模块""" + +import os +import json +import csv +from typing import List, Dict, Any + +def read_file(filepath, encoding='utf-8'): + """读取文本文件""" + try: + with open(filepath, 'r', encoding=encoding) as file: + return file.read() + except FileNotFoundError: + print(f"文件 {filepath} 不存在") + return None + except Exception as e: + print(f"读取文件时出错:{e}") + return None + +def write_file(filepath, content, encoding='utf-8'): + """写入文本文件""" + try: + # 确保目录存在 + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, 'w', encoding=encoding) as file: + file.write(content) + return True + except Exception as e: + print(f"写入文件时出错:{e}") + return False + +def read_json(filepath): + """读取JSON文件""" + try: + with open(filepath, 'r', encoding='utf-8') as file: + return json.load(file) + except Exception as e: + print(f"读取JSON文件时出错:{e}") + return None + +def write_json(filepath, data, indent=2): + """写入JSON文件""" + try: + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, 'w', encoding='utf-8') as file: + json.dump(data, file, indent=indent, ensure_ascii=False) + return True + except Exception as e: + print(f"写入JSON文件时出错:{e}") + return False + +def read_csv(filepath): + """读取CSV文件""" + try: + with open(filepath, 'r', encoding='utf-8') as file: + reader = csv.DictReader(file) + return list(reader) + except Exception as e: + print(f"读取CSV文件时出错:{e}") + return None + +def write_csv(filepath, data, fieldnames=None): + """写入CSV文件""" + try: + if not data: + return False + + if fieldnames is None: + fieldnames = data[0].keys() if isinstance(data[0], dict) else None + + os.makedirs(os.path.dirname(filepath), exist_ok=True) + with open(filepath, 'w', newline='', encoding='utf-8') as file: + writer = csv.DictWriter(file, fieldnames=fieldnames) + writer.writeheader() + writer.writerows(data) + return True + except Exception as e: + print(f"写入CSV文件时出错:{e}") + return False + +def get_file_info(filepath): + """获取文件信息""" + try: + stat = os.stat(filepath) + return { + 'size': stat.st_size, + 'modified': stat.st_mtime, + 'created': stat.st_ctime, + 'is_file': os.path.isfile(filepath), + 'is_dir': os.path.isdir(filepath) + } + except Exception as e: + print(f"获取文件信息时出错:{e}") + return None + +class FileManager: + """文件管理器类""" + + def __init__(self, base_path='.'): + self.base_path = base_path + + def list_files(self, extension=None): + """列出目录中的文件""" + files = [] + for item in os.listdir(self.base_path): + item_path = os.path.join(self.base_path, item) + if os.path.isfile(item_path): + if extension is None or item.endswith(extension): + files.append(item) + return files + + def create_backup(self, filepath): + """创建文件备份""" + backup_path = filepath + '.backup' + try: + content = read_file(filepath) + if content is not None: + return write_file(backup_path, content) + except Exception as e: + print(f"创建备份时出错:{e}") + return False +``` + +```python +# utils/data_utils.py +"""数据处理工具模块""" + +from typing import List, Dict, Any, Union +from collections import Counter +import statistics + +class DataProcessor: + """数据处理器类""" + + def __init__(self, data: List[Any] = None): + self.data = data or [] + + def add_data(self, item: Any): + """添加数据项""" + self.data.append(item) + + def filter_data(self, condition): + """过滤数据""" + return [item for item in self.data if condition(item)] + + def map_data(self, transform): + """转换数据""" + return [transform(item) for item in self.data] + + def group_by(self, key_func): + """按条件分组""" + groups = {} + for item in self.data: + key = key_func(item) + if key not in groups: + groups[key] = [] + groups[key].append(item) + return groups + + def get_statistics(self): + """获取数值数据的统计信息""" + if not self.data or not all(isinstance(x, (int, float)) for x in self.data): + return None + + return { + 'count': len(self.data), + 'sum': sum(self.data), + 'mean': statistics.mean(self.data), + 'median': statistics.median(self.data), + 'mode': statistics.mode(self.data) if len(set(self.data)) < len(self.data) else None, + 'min': min(self.data), + 'max': max(self.data), + 'range': max(self.data) - min(self.data) + } + +def clean_data(data: List[Dict[str, Any]], required_fields: List[str]) -> List[Dict[str, Any]]: + """清理数据,移除缺少必需字段的记录""" + cleaned = [] + for record in data: + if all(field in record and record[field] is not None for field in required_fields): + cleaned.append(record) + return cleaned + +def aggregate_data(data: List[Dict[str, Any]], group_by: str, aggregate_field: str, operation: str = 'sum'): + """聚合数据""" + groups = {} + + for record in data: + key = record.get(group_by) + if key not in groups: + groups[key] = [] + groups[key].append(record.get(aggregate_field, 0)) + + result = {} + for key, values in groups.items(): + if operation == 'sum': + result[key] = sum(values) + elif operation == 'avg': + result[key] = sum(values) / len(values) if values else 0 + elif operation == 'count': + result[key] = len(values) + elif operation == 'max': + result[key] = max(values) if values else 0 + elif operation == 'min': + result[key] = min(values) if values else 0 + + return result + +def find_duplicates(data: List[Any]) -> List[Any]: + """查找重复项""" + counter = Counter(data) + return [item for item, count in counter.items() if count > 1] + +def remove_duplicates(data: List[Any]) -> List[Any]: + """移除重复项,保持顺序""" + seen = set() + result = [] + for item in data: + if item not in seen: + seen.add(item) + result.append(item) + return result + +def sort_data(data: List[Dict[str, Any]], sort_by: str, reverse: bool = False) -> List[Dict[str, Any]]: + """排序数据""" + return sorted(data, key=lambda x: x.get(sort_by, 0), reverse=reverse) +``` + +```python +# utils/math/__init__.py +"""数学工具子包""" + +from .basic import * +from .advanced import * + +__all__ = ['add', 'subtract', 'multiply', 'divide', 'power', 'sqrt', 'log', 'sin', 'cos'] +``` + +```python +# utils/math/basic.py +"""基础数学运算""" + +def add(x, y): + """加法""" + return x + y + +def subtract(x, y): + """减法""" + return x - y + +def multiply(x, y): + """乘法""" + return x * y + +def divide(x, y): + """除法""" + if y == 0: + raise ValueError("除数不能为零") + return x / y + +def power(base, exponent): + """幂运算""" + return base ** exponent +``` + +```python +# utils/math/advanced.py +"""高级数学运算""" + +import math + +def sqrt(x): + """平方根""" + if x < 0: + raise ValueError("负数不能开平方根") + return math.sqrt(x) + +def log(x, base=math.e): + """对数""" + if x <= 0: + raise ValueError("对数的参数必须大于0") + return math.log(x, base) + +def sin(x): + """正弦""" + return math.sin(x) + +def cos(x): + """余弦""" + return math.cos(x) + +def tan(x): + """正切""" + return math.tan(x) +``` + +### 3.3 使用包 + +```python +# 使用我们创建的工具包 + +# 导入整个包 +import utils + +# 使用包级别的函数 +info = utils.get_package_info() +print(f"包信息:{info}") + +# 使用字符串工具 +text = "hello world python programming" +result = utils.capitalize_words(text) +print(f"首字母大写:{result}") + +# 使用文件工具 +utils.write_file('test.txt', 'Hello, World!') +content = utils.read_file('test.txt') +print(f"文件内容:{content}") + +# 使用数据处理器 +processor = utils.DataProcessor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) +even_numbers = processor.filter_data(lambda x: x % 2 == 0) +print(f"偶数:{even_numbers}") + +stats = processor.get_statistics() +print(f"统计信息:{stats}") + +# 导入子包 +from utils.math import add, multiply, sqrt + +result1 = add(10, 5) +result2 = multiply(6, 7) +result3 = sqrt(16) +print(f"数学运算:{result1}, {result2}, {result3}") + +# 使用别名导入 +from utils.string_utils import StringProcessor as SP + +processor = SP("hello world hello python") +result = processor.process(['capitalize', 'remove_duplicates']) +print(f"字符串处理结果:{result}") +``` + +--- + +## 四、标准库模块 + +### 4.1 常用标准库模块 + +```python +# os模块 - 操作系统接口 +import os + +print(f"当前工作目录:{os.getcwd()}") +print(f"用户主目录:{os.path.expanduser('~')}") +print(f"路径分隔符:{os.sep}") + +# 环境变量 +print(f"PATH环境变量:{os.environ.get('PATH', '未设置')}") + +# 文件和目录操作 +if not os.path.exists('temp_dir'): + os.makedirs('temp_dir') + print("创建了临时目录") + +# sys模块 - 系统相关参数和函数 +import sys + +print(f"Python版本:{sys.version}") +print(f"平台:{sys.platform}") +print(f"命令行参数:{sys.argv}") + +# datetime模块 - 日期和时间 +from datetime import datetime, date, time, timedelta + +now = datetime.now() +print(f"当前时间:{now}") +print(f"格式化时间:{now.strftime('%Y-%m-%d %H:%M:%S')}") + +# 时间计算 +tomorrow = now + timedelta(days=1) +print(f"明天:{tomorrow.strftime('%Y-%m-%d')}") + +# random模块 - 随机数生成 +import random + +print(f"随机整数:{random.randint(1, 100)}") +print(f"随机浮点数:{random.random()}") +print(f"随机选择:{random.choice(['apple', 'banana', 'orange'])}") + +# 随机打乱列表 +numbers = [1, 2, 3, 4, 5] +random.shuffle(numbers) +print(f"打乱后的列表:{numbers}") + +# json模块 - JSON数据处理 +import json + +data = { + 'name': '张三', + 'age': 25, + 'skills': ['Python', 'JavaScript', 'SQL'] +} + +# 转换为JSON字符串 +json_str = json.dumps(data, ensure_ascii=False, indent=2) +print(f"JSON字符串:\n{json_str}") + +# 从JSON字符串解析 +parsed_data = json.loads(json_str) +print(f"解析后的数据:{parsed_data}") +``` + +### 4.2 更多实用标准库 + +```python +# collections模块 - 特殊容器数据类型 +from collections import Counter, defaultdict, namedtuple, deque + +# Counter - 计数器 +text = "hello world" +letter_count = Counter(text) +print(f"字母计数:{letter_count}") +print(f"最常见的3个字母:{letter_count.most_common(3)}") + +# defaultdict - 默认字典 +dd = defaultdict(list) +dd['fruits'].append('apple') +dd['fruits'].append('banana') +dd['vegetables'].append('carrot') +print(f"默认字典:{dict(dd)}") + +# namedtuple - 命名元组 +Point = namedtuple('Point', ['x', 'y']) +p = Point(3, 4) +print(f"点坐标:{p}, x={p.x}, y={p.y}") + +# deque - 双端队列 +dq = deque([1, 2, 3]) +dq.appendleft(0) +dq.append(4) +print(f"双端队列:{list(dq)}") + +# itertools模块 - 迭代工具 +import itertools + +# 组合和排列 +data = ['A', 'B', 'C'] +combinations = list(itertools.combinations(data, 2)) +permutations = list(itertools.permutations(data, 2)) +print(f"组合:{combinations}") +print(f"排列:{permutations}") + +# 无限迭代器 +counter = itertools.count(1, 2) # 从1开始,步长为2 +first_5_odd = [next(counter) for _ in range(5)] +print(f"前5个奇数:{first_5_odd}") + +# re模块 - 正则表达式 +import re + +text = "联系电话:138-1234-5678,邮箱:user@example.com" + +# 查找电话号码 +phone_pattern = r'\d{3}-\d{4}-\d{4}' +phone = re.search(phone_pattern, text) +if phone: + print(f"找到电话号码:{phone.group()}") + +# 查找邮箱 +email_pattern = r'\w+@\w+\.\w+' +email = re.search(email_pattern, text) +if email: + print(f"找到邮箱:{email.group()}") + +# 替换文本 +cleaned_text = re.sub(r'\d{3}-\d{4}-\d{4}', '[电话已隐藏]', text) +print(f"清理后的文本:{cleaned_text}") + +# pathlib模块 - 面向对象的路径操作 +from pathlib import Path + +# 创建路径对象 +path = Path('data/files/document.txt') +print(f"文件名:{path.name}") +print(f"文件扩展名:{path.suffix}") +print(f"父目录:{path.parent}") +print(f"绝对路径:{path.absolute()}") + +# 路径操作 +new_path = path.with_suffix('.pdf') +print(f"更改扩展名后:{new_path}") + +# 检查路径 +print(f"路径存在吗?{path.exists()}") +print(f"是文件吗?{path.is_file()}") +print(f"是目录吗?{path.is_dir()}") +``` + +--- + +## 五、第三方包管理 + +### 5.1 pip包管理器 + +```bash +# 安装包 +pip install requests +pip install pandas numpy matplotlib + +# 安装特定版本 +pip install django==3.2.0 + +# 从requirements.txt安装 +pip install -r requirements.txt + +# 升级包 +pip upgrade requests + +# 卸载包 +pip uninstall requests + +# 列出已安装的包 +pip list + +# 显示包信息 +pip show requests + +# 生成requirements.txt +pip freeze > requirements.txt +``` + +### 5.2 虚拟环境 + +```bash +# 创建虚拟环境 +python -m venv myenv + +# 激活虚拟环境 +# Windows +myenv\Scripts\activate +# macOS/Linux +source myenv/bin/activate + +# 停用虚拟环境 +deactivate + +# 删除虚拟环境 +rmdir /s myenv # Windows +rm -rf myenv # macOS/Linux +``` + +### 5.3 常用第三方包示例 + +```python +# requests - HTTP库 +import requests + +response = requests.get('https://api.github.com/users/octocat') +if response.status_code == 200: + data = response.json() + print(f"用户名:{data['login']}") + print(f"公开仓库数:{data['public_repos']}") + +# pandas - 数据分析 +import pandas as pd + +# 创建DataFrame +data = { + 'name': ['Alice', 'Bob', 'Charlie'], + 'age': [25, 30, 35], + 'city': ['北京', '上海', '广州'] +} +df = pd.DataFrame(data) +print(df) + +# 数据操作 +print(f"平均年龄:{df['age'].mean()}") +print(f"年龄大于25的人:\n{df[df['age'] > 25]}") + +# matplotlib - 绘图 +import matplotlib.pyplot as plt +import numpy as np + +x = np.linspace(0, 10, 100) +y = np.sin(x) + +plt.figure(figsize=(10, 6)) +plt.plot(x, y, label='sin(x)') +plt.xlabel('x') +plt.ylabel('y') +plt.title('正弦函数图像') +plt.legend() +plt.grid(True) +plt.show() +``` + +--- + +## 六、模块最佳实践 + +### 6.1 模块设计原则 + +```python +# 好的模块设计示例 +"""用户管理模块 + +这个模块提供用户注册、登录、权限管理等功能。 + +示例用法: + from user_manager import User, authenticate + + user = User('alice', 'alice@example.com') + user.set_password('secret123') + + if authenticate('alice', 'secret123'): + print('登录成功') +""" + +import hashlib +import json +from datetime import datetime +from typing import Optional, Dict, List + +# 模块级常量 +DEFAULT_ROLE = 'user' +ADMIN_ROLE = 'admin' +MAX_LOGIN_ATTEMPTS = 3 + +# 私有函数(以下划线开头) +def _hash_password(password: str) -> str: + """私有函数:密码哈希""" + return hashlib.sha256(password.encode()).hexdigest() + +def _validate_email(email: str) -> bool: + """私有函数:邮箱验证""" + import re + pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$' + return re.match(pattern, email) is not None + +class User: + """用户类""" + + def __init__(self, username: str, email: str, role: str = DEFAULT_ROLE): + if not username or not email: + raise ValueError("用户名和邮箱不能为空") + + if not _validate_email(email): + raise ValueError("邮箱格式不正确") + + self.username = username + self.email = email + self.role = role + self.password_hash = None + self.created_at = datetime.now() + self.last_login = None + self.login_attempts = 0 + self.is_active = True + + def set_password(self, password: str) -> None: + """设置密码""" + if len(password) < 6: + raise ValueError("密码长度至少6位") + self.password_hash = _hash_password(password) + + def check_password(self, password: str) -> bool: + """检查密码""" + if not self.password_hash: + return False + return self.password_hash == _hash_password(password) + + def to_dict(self) -> Dict: + """转换为字典""" + return { + 'username': self.username, + 'email': self.email, + 'role': self.role, + 'created_at': self.created_at.isoformat(), + 'last_login': self.last_login.isoformat() if self.last_login else None, + 'is_active': self.is_active + } + + def __str__(self): + return f"User(username='{self.username}', email='{self.email}', role='{self.role}')" + + def __repr__(self): + return self.__str__() + +class UserManager: + """用户管理器""" + + def __init__(self): + self.users: Dict[str, User] = {} + + def register(self, username: str, email: str, password: str, role: str = DEFAULT_ROLE) -> User: + """注册用户""" + if username in self.users: + raise ValueError(f"用户名 '{username}' 已存在") + + user = User(username, email, role) + user.set_password(password) + self.users[username] = user + return user + + def authenticate(self, username: str, password: str) -> Optional[User]: + """用户认证""" + user = self.users.get(username) + if not user or not user.is_active: + return None + + if user.login_attempts >= MAX_LOGIN_ATTEMPTS: + raise ValueError("登录尝试次数过多,账户已锁定") + + if user.check_password(password): + user.last_login = datetime.now() + user.login_attempts = 0 + return user + else: + user.login_attempts += 1 + return None + + def get_user(self, username: str) -> Optional[User]: + """获取用户""" + return self.users.get(username) + + def list_users(self, role: Optional[str] = None) -> List[User]: + """列出用户""" + if role: + return [user for user in self.users.values() if user.role == role] + return list(self.users.values()) + + def export_users(self, filepath: str) -> bool: + """导出用户数据""" + try: + data = [user.to_dict() for user in self.users.values()] + with open(filepath, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2, ensure_ascii=False) + return True + except Exception as e: + print(f"导出用户数据失败:{e}") + return False + +# 模块级实例(单例模式) +_user_manager = UserManager() + +# 公共API函数 +def register_user(username: str, email: str, password: str, role: str = DEFAULT_ROLE) -> User: + """注册用户(模块级函数)""" + return _user_manager.register(username, email, password, role) + +def authenticate(username: str, password: str) -> Optional[User]: + """用户认证(模块级函数)""" + return _user_manager.authenticate(username, password) + +def get_user(username: str) -> Optional[User]: + """获取用户(模块级函数)""" + return _user_manager.get_user(username) + +def list_users(role: Optional[str] = None) -> List[User]: + """列出用户(模块级函数)""" + return _user_manager.list_users(role) + +# 定义模块的公共接口 +__all__ = [ + 'User', + 'UserManager', + 'register_user', + 'authenticate', + 'get_user', + 'list_users', + 'DEFAULT_ROLE', + 'ADMIN_ROLE' +] + +# 模块测试代码 +if __name__ == "__main__": + # 测试用户管理功能 + print("测试用户管理模块:") + + # 注册用户 + alice = register_user('alice', 'alice@example.com', 'password123') + bob = register_user('bob', 'bob@example.com', 'secret456', ADMIN_ROLE) + + print(f"注册用户:{alice}") + print(f"注册管理员:{bob}") + + # 用户认证 + auth_user = authenticate('alice', 'password123') + if auth_user: + print(f"认证成功:{auth_user.username}") + + # 列出用户 + all_users = list_users() + print(f"所有用户:{[user.username for user in all_users]}") + + admin_users = list_users(ADMIN_ROLE) + print(f"管理员用户:{[user.username for user in admin_users]}") +``` + +### 6.2 模块文档和测试 + +```python +# 文档字符串最佳实践 +def calculate_distance(point1, point2): + """计算两点之间的欧几里得距离。 + + Args: + point1 (tuple): 第一个点的坐标 (x, y) + point2 (tuple): 第二个点的坐标 (x, y) + + Returns: + float: 两点之间的距离 + + Raises: + ValueError: 当输入不是有效坐标时 + TypeError: 当输入类型不正确时 + + Examples: + >>> calculate_distance((0, 0), (3, 4)) + 5.0 + >>> calculate_distance((1, 1), (4, 5)) + 5.0 + """ + try: + x1, y1 = point1 + x2, y2 = point2 + return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 + except (ValueError, TypeError) as e: + raise ValueError(f"无效的坐标输入: {e}") + +# 单元测试示例 +import unittest + +class TestMathUtils(unittest.TestCase): + """数学工具模块测试""" + + def test_calculate_distance(self): + """测试距离计算""" + # 测试正常情况 + self.assertEqual(calculate_distance((0, 0), (3, 4)), 5.0) + self.assertEqual(calculate_distance((1, 1), (1, 1)), 0.0) + + # 测试异常情况 + with self.assertRaises(ValueError): + calculate_distance((1, 2), (3,)) # 坐标不完整 + + with self.assertRaises(ValueError): + calculate_distance("invalid", (1, 2)) # 无效类型 + +if __name__ == "__main__": + unittest.main() +``` + +--- + +## 七、实战项目:个人任务管理系统 + +让我们创建一个完整的任务管理系统来实践模块化编程: + +```python +# task_manager/ +# __init__.py +# models.py +# storage.py +# cli.py +# utils.py + +# task_manager/__init__.py +"""个人任务管理系统 + +一个简单而强大的任务管理工具。 +""" + +__version__ = "1.0.0" +__author__ = "哪吒" + +from .models import Task, TaskManager +from .storage import FileStorage, JSONStorage +from .utils import format_date, get_priority_color + +__all__ = ['Task', 'TaskManager', 'FileStorage', 'JSONStorage', 'format_date', 'get_priority_color'] +``` + +```python +# task_manager/models.py +"""任务模型""" + +from datetime import datetime, date +from typing import List, Optional, Dict, Any +from enum import Enum + +class Priority(Enum): + """任务优先级""" + LOW = 1 + MEDIUM = 2 + HIGH = 3 + URGENT = 4 + +class Status(Enum): + """任务状态""" + TODO = "待办" + IN_PROGRESS = "进行中" + COMPLETED = "已完成" + CANCELLED = "已取消" + +class Task: + """任务类""" + + def __init__(self, title: str, description: str = "", priority: Priority = Priority.MEDIUM, + due_date: Optional[date] = None, tags: Optional[List[str]] = None): + self.id = self._generate_id() + self.title = title + self.description = description + self.priority = priority + self.status = Status.TODO + self.created_at = datetime.now() + self.updated_at = datetime.now() + self.due_date = due_date + self.completed_at = None + self.tags = tags or [] + + def _generate_id(self) -> str: + """生成唯一ID""" + import uuid + return str(uuid.uuid4())[:8] + + def mark_completed(self): + """标记为已完成""" + self.status = Status.COMPLETED + self.completed_at = datetime.now() + self.updated_at = datetime.now() + + def mark_in_progress(self): + """标记为进行中""" + self.status = Status.IN_PROGRESS + self.updated_at = datetime.now() + + def mark_cancelled(self): + """标记为已取消""" + self.status = Status.CANCELLED + self.updated_at = datetime.now() + + def update(self, title: Optional[str] = None, description: Optional[str] = None, + priority: Optional[Priority] = None, due_date: Optional[date] = None, + tags: Optional[List[str]] = None): + """更新任务信息""" + if title is not None: + self.title = title + if description is not None: + self.description = description + if priority is not None: + self.priority = priority + if due_date is not None: + self.due_date = due_date + if tags is not None: + self.tags = tags + self.updated_at = datetime.now() + + def add_tag(self, tag: str): + """添加标签""" + if tag not in self.tags: + self.tags.append(tag) + self.updated_at = datetime.now() + + def remove_tag(self, tag: str): + """移除标签""" + if tag in self.tags: + self.tags.remove(tag) + self.updated_at = datetime.now() + + def is_overdue(self) -> bool: + """检查是否过期""" + if self.due_date and self.status not in [Status.COMPLETED, Status.CANCELLED]: + return date.today() > self.due_date + return False + + def days_until_due(self) -> Optional[int]: + """距离截止日期的天数""" + if self.due_date: + delta = self.due_date - date.today() + return delta.days + return None + + def to_dict(self) -> Dict[str, Any]: + """转换为字典""" + 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(), + 'due_date': self.due_date.isoformat() if self.due_date else None, + 'completed_at': self.completed_at.isoformat() if self.completed_at else None, + 'tags': self.tags + } + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'Task': + """从字典创建任务""" + task = cls.__new__(cls) + task.id = data['id'] + task.title = data['title'] + task.description = data['description'] + task.priority = Priority(data['priority']) + task.status = Status(data['status']) + task.created_at = datetime.fromisoformat(data['created_at']) + task.updated_at = datetime.fromisoformat(data['updated_at']) + task.due_date = date.fromisoformat(data['due_date']) if data['due_date'] else None + task.completed_at = datetime.fromisoformat(data['completed_at']) if data['completed_at'] else None + task.tags = data['tags'] + return task + + def __str__(self): + status_icon = { + Status.TODO: "⭕", + Status.IN_PROGRESS: "🔄", + Status.COMPLETED: "✅", + Status.CANCELLED: "❌" + } + priority_icon = { + Priority.LOW: "🟢", + Priority.MEDIUM: "🟡", + Priority.HIGH: "🟠", + Priority.URGENT: "🔴" + } + + due_info = f" (截止: {self.due_date})" if self.due_date else "" + tags_info = f" #{' #'.join(self.tags)}" if self.tags else "" + + return f"{status_icon[self.status]} {priority_icon[self.priority]} {self.title}{due_info}{tags_info}" + +class TaskManager: + """任务管理器""" + + def __init__(self): + self.tasks: Dict[str, Task] = {} + + def add_task(self, title: str, description: str = "", priority: Priority = Priority.MEDIUM, + due_date: Optional[date] = None, tags: Optional[List[str]] = None) -> Task: + """添加任务""" + task = Task(title, description, priority, due_date, tags) + self.tasks[task.id] = task + return task + + def get_task(self, task_id: str) -> Optional[Task]: + """获取任务""" + return self.tasks.get(task_id) + + def update_task(self, task_id: str, **kwargs) -> bool: + """更新任务""" + task = self.get_task(task_id) + if task: + task.update(**kwargs) + return True + return False + + def delete_task(self, task_id: str) -> bool: + """删除任务""" + if task_id in self.tasks: + del self.tasks[task_id] + return True + return False + + def list_tasks(self, status: Optional[Status] = None, priority: Optional[Priority] = None, + tag: Optional[str] = None, overdue_only: bool = False) -> List[Task]: + """列出任务""" + tasks = list(self.tasks.values()) + + if status: + tasks = [t for t in tasks if t.status == status] + + if priority: + tasks = [t for t in tasks if t.priority == priority] + + if tag: + tasks = [t for t in tasks if tag in t.tags] + + if overdue_only: + tasks = [t for t in tasks if t.is_overdue()] + + return sorted(tasks, key=lambda t: (t.priority.value, t.created_at), reverse=True) + + def search_tasks(self, keyword: str) -> List[Task]: + """搜索任务""" + keyword = keyword.lower() + return [task for task in self.tasks.values() + if keyword in task.title.lower() or keyword in task.description.lower()] + + def get_statistics(self) -> Dict[str, Any]: + """获取统计信息""" + total = len(self.tasks) + completed = len([t for t in self.tasks.values() if t.status == Status.COMPLETED]) + in_progress = len([t for t in self.tasks.values() if t.status == Status.IN_PROGRESS]) + overdue = len([t for t in self.tasks.values() if t.is_overdue()]) + + return { + 'total': total, + 'completed': completed, + 'in_progress': in_progress, + 'todo': total - completed - in_progress, + 'overdue': overdue, + 'completion_rate': (completed / total * 100) if total > 0 else 0 + } + + def get_tasks_by_date(self, target_date: date) -> List[Task]: + """获取指定日期的任务""" + return [task for task in self.tasks.values() if task.due_date == target_date] + + def get_upcoming_tasks(self, days: int = 7) -> List[Task]: + """获取即将到期的任务""" + upcoming = [] + for task in self.tasks.values(): + if task.due_date and task.status not in [Status.COMPLETED, Status.CANCELLED]: + days_until = task.days_until_due() + if days_until is not None and 0 <= days_until <= days: + upcoming.append(task) + return sorted(upcoming, key=lambda t: t.due_date) +``` + +--- + +## 八、总结 + +### 8.1 模块系统的核心概念 + +1. **模块**:包含Python代码的文件 +2. **包**:包含多个模块的目录 +3. **导入**:使用其他模块的功能 +4. **命名空间**:避免名称冲突 +5. **搜索路径**:Python查找模块的位置 + +### 8.2 最佳实践总结 + +1. **模块设计**: + - 单一职责原则 + - 清晰的接口设计 + - 完善的文档字符串 + - 合理的错误处理 + +2. **包组织**: + - 逻辑清晰的目录结构 + - 适当的`__init__.py`文件 + - 明确的`__all__`定义 + +3. **导入规范**: + - 优先使用具体导入 + - 避免循环导入 + - 合理使用别名 + +4. **代码质量**: + - 编写单元测试 + - 使用类型注解 + - 遵循PEP 8规范 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Python/9.md b/docs/Python/9.md new file mode 100644 index 000000000..d24af54a2 --- /dev/null +++ b/docs/Python/9.md @@ -0,0 +1,1979 @@ +--- +title: 第9天-面向对象编程 +author: 哪吒 +date: '2023-06-15' +--- + +# 第9天-Python面向对象编程 + +欢迎来到Python面向对象编程的世界!面向对象编程(Object-Oriented Programming,OOP)是一种强大的编程范式,它让我们能够创建更加模块化、可重用和易维护的代码。 + +## 什么是面向对象编程? + +面向对象编程是一种编程范式,它将数据和操作数据的方法组织在一起,形成"对象"。这种方式更接近我们对现实世界的理解。 + +> **生活类比**: +> - **类(Class)**:像汽车的设计图纸,定义了汽车应该有什么属性和功能 +> - **对象(Object)**:像根据图纸制造出的具体汽车 +> - **属性(Attribute)**:像汽车的颜色、品牌、型号 +> - **方法(Method)**:像汽车的启动、加速、刹车功能 + +### OOP的四大特性 + +1. **封装(Encapsulation)**:将数据和方法包装在一起,隐藏内部实现细节 +2. **继承(Inheritance)**:子类可以继承父类的属性和方法 +3. **多态(Polymorphism)**:同一个方法在不同类中有不同的实现 +4. **抽象(Abstraction)**:隐藏复杂的实现细节,只暴露必要的接口 + +--- + +## 一、类和对象基础 + +### 1.1 定义类 + +```python +# 定义一个简单的学生类 +class Student: + """学生类 + + 这个类用来表示一个学生,包含学生的基本信息和行为。 + """ + + # 类变量(所有实例共享) + school = "Python编程学院" + student_count = 0 + + def __init__(self, name, age, student_id): + """构造方法(初始化方法) + + Args: + name (str): 学生姓名 + age (int): 学生年龄 + student_id (str): 学号 + """ + # 实例变量(每个实例独有) + self.name = name + self.age = age + self.student_id = student_id + self.grades = {} # 存储各科成绩 + self.is_enrolled = True + + # 每创建一个学生,计数器加1 + Student.student_count += 1 + + def introduce(self): + """自我介绍方法""" + return f"大家好,我是{self.name},今年{self.age}岁,学号是{self.student_id}" + + def add_grade(self, subject, score): + """添加成绩 + + Args: + subject (str): 科目名称 + score (float): 成绩分数 + """ + if 0 <= score <= 100: + self.grades[subject] = score + print(f"已为{self.name}添加{subject}成绩:{score}分") + else: + print("成绩必须在0-100之间") + + def get_average_grade(self): + """计算平均成绩 + + Returns: + float: 平均成绩,如果没有成绩则返回0 + """ + if not self.grades: + return 0 + return sum(self.grades.values()) / len(self.grades) + + def get_grade_level(self): + """根据平均成绩获取等级 + + Returns: + str: 成绩等级 + """ + avg = self.get_average_grade() + if avg >= 90: + return "优秀" + elif avg >= 80: + return "良好" + elif avg >= 70: + return "中等" + elif avg >= 60: + return "及格" + else: + return "不及格" + + def enroll(self): + """注册入学""" + self.is_enrolled = True + print(f"{self.name}已成功注册入学") + + def withdraw(self): + """退学""" + self.is_enrolled = False + print(f"{self.name}已办理退学手续") + + @classmethod + def get_student_count(cls): + """类方法:获取学生总数 + + Returns: + int: 当前学生总数 + """ + return cls.student_count + + @classmethod + def create_from_string(cls, student_info): + """类方法:从字符串创建学生对象 + + Args: + student_info (str): 格式为 "姓名,年龄,学号" 的字符串 + + Returns: + Student: 新创建的学生对象 + """ + name, age, student_id = student_info.split(',') + return cls(name.strip(), int(age.strip()), student_id.strip()) + + @staticmethod + def is_valid_student_id(student_id): + """静态方法:验证学号格式 + + Args: + student_id (str): 学号 + + Returns: + bool: 学号是否有效 + """ + # 假设学号格式为:年份 + 4位数字 + return len(student_id) == 8 and student_id.isdigit() + + def __str__(self): + """字符串表示方法""" + status = "在读" if self.is_enrolled else "已退学" + return f"学生({self.name}, {self.age}岁, {self.student_id}, {status})" + + def __repr__(self): + """开发者友好的字符串表示""" + return f"Student('{self.name}', {self.age}, '{self.student_id}')" + + def __eq__(self, other): + """相等性比较""" + if isinstance(other, Student): + return self.student_id == other.student_id + return False + + def __lt__(self, other): + """小于比较(按平均成绩)""" + if isinstance(other, Student): + return self.get_average_grade() < other.get_average_grade() + return NotImplemented + +# 使用示例 +print("=== 创建学生对象 ===") +# 创建学生对象 +student1 = Student("张三", 20, "20230001") +student2 = Student("李四", 19, "20230002") +student3 = Student("王五", 21, "20230003") + +print(student1) +print(student2) +print(student3) + +print(f"\n当前学生总数:{Student.get_student_count()}") +print(f"学校名称:{Student.school}") + +print("\n=== 学生自我介绍 ===") +print(student1.introduce()) +print(student2.introduce()) + +print("\n=== 添加成绩 ===") +student1.add_grade("数学", 95) +student1.add_grade("英语", 87) +student1.add_grade("物理", 92) + +student2.add_grade("数学", 78) +student2.add_grade("英语", 85) +student2.add_grade("物理", 80) + +print(f"\n{student1.name}的平均成绩:{student1.get_average_grade():.2f}分,等级:{student1.get_grade_level()}") +print(f"{student2.name}的平均成绩:{student2.get_average_grade():.2f}分,等级:{student2.get_grade_level()}") + +print("\n=== 使用类方法和静态方法 ===") +# 使用类方法创建学生 +student4 = Student.create_from_string("赵六, 22, 20230004") +print(f"从字符串创建的学生:{student4}") + +# 使用静态方法验证学号 +print(f"学号20230001是否有效:{Student.is_valid_student_id('20230001')}") +print(f"学号123是否有效:{Student.is_valid_student_id('123')}") + +print("\n=== 对象比较 ===") +print(f"student1 == student2: {student1 == student2}") +print(f"student1 < student2: {student1 < student2}") +``` + +### 1.2 属性访问控制 + +```python +class BankAccount: + """银行账户类 - 演示封装和属性访问控制""" + + def __init__(self, account_number, owner_name, initial_balance=0): + self.account_number = account_number # 公开属性 + self.owner_name = owner_name # 公开属性 + self._balance = initial_balance # 受保护属性(约定:单下划线) + self.__pin = None # 私有属性(双下划线) + self.__transaction_history = [] # 私有属性 + + def set_pin(self, pin): + """设置PIN码""" + if isinstance(pin, str) and len(pin) == 4 and pin.isdigit(): + self.__pin = pin + print("PIN码设置成功") + else: + print("PIN码必须是4位数字") + + def verify_pin(self, pin): + """验证PIN码""" + return self.__pin == pin + + def deposit(self, amount, pin): + """存款""" + if not self.verify_pin(pin): + print("PIN码错误") + return False + + if amount > 0: + self._balance += amount + self.__add_transaction("存款", amount) + print(f"存款成功,当前余额:{self._balance}元") + return True + else: + print("存款金额必须大于0") + return False + + def withdraw(self, amount, pin): + """取款""" + if not self.verify_pin(pin): + print("PIN码错误") + return False + + if amount > 0 and amount <= self._balance: + self._balance -= amount + self.__add_transaction("取款", -amount) + print(f"取款成功,当前余额:{self._balance}元") + return True + else: + print("取款金额无效或余额不足") + return False + + def get_balance(self, pin): + """查询余额""" + if not self.verify_pin(pin): + print("PIN码错误") + return None + return self._balance + + def get_transaction_history(self, pin): + """获取交易历史""" + if not self.verify_pin(pin): + print("PIN码错误") + return None + return self.__transaction_history.copy() + + def __add_transaction(self, transaction_type, amount): + """私有方法:添加交易记录""" + from datetime import datetime + transaction = { + 'type': transaction_type, + 'amount': amount, + 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'balance_after': self._balance + } + self.__transaction_history.append(transaction) + + def __str__(self): + return f"银行账户({self.account_number}, {self.owner_name})" + +# 使用示例 +print("=== 银行账户示例 ===") +account = BankAccount("6222001234567890", "张三", 1000) +print(account) + +# 设置PIN码 +account.set_pin("1234") + +# 存款 +account.deposit(500, "1234") + +# 取款 +account.withdraw(200, "1234") + +# 查询余额 +balance = account.get_balance("1234") +print(f"当前余额:{balance}元") + +# 查看交易历史 +history = account.get_transaction_history("1234") +print("\n交易历史:") +for transaction in history: + print(f"{transaction['timestamp']} - {transaction['type']}: {transaction['amount']}元, 余额: {transaction['balance_after']}元") + +# 尝试直接访问私有属性(会失败) +print("\n=== 属性访问测试 ===") +print(f"公开属性 - 账户号码:{account.account_number}") +print(f"受保护属性 - 余额:{account._balance}") + +# 尝试访问私有属性(Python会进行名称修饰) +try: + print(account.__pin) # 这会引发AttributeError +except AttributeError as e: + print(f"无法直接访问私有属性:{e}") + +# 实际上私有属性被修饰为 _ClassName__attributeName +print(f"通过名称修饰访问私有属性:{account._BankAccount__pin}") +``` + +--- + +## 二、继承 + +### 2.1 基本继承 + +```python +# 基类(父类) +class Animal: + """动物基类""" + + def __init__(self, name, species, age): + self.name = name + self.species = species + self.age = age + self.is_alive = True + + def eat(self, food): + """吃东西""" + print(f"{self.name}正在吃{food}") + + def sleep(self): + """睡觉""" + print(f"{self.name}正在睡觉") + + def make_sound(self): + """发出声音(基类中的通用实现)""" + print(f"{self.name}发出了声音") + + def get_info(self): + """获取动物信息""" + status = "活着" if self.is_alive else "已死亡" + return f"{self.name}是一只{self.age}岁的{self.species},目前{status}" + + def __str__(self): + return f"{self.species}({self.name})" + +# 派生类(子类) +class Dog(Animal): + """狗类 - 继承自Animal""" + + def __init__(self, name, breed, age, owner=None): + # 调用父类的构造方法 + super().__init__(name, "狗", age) + self.breed = breed # 狗特有的属性 + self.owner = owner + self.is_trained = False + + def make_sound(self): + """重写父类方法 - 狗的叫声""" + print(f"{self.name}汪汪叫") + + def wag_tail(self): + """狗特有的方法 - 摇尾巴""" + print(f"{self.name}开心地摇尾巴") + + def fetch(self, item): + """狗特有的方法 - 捡东西""" + print(f"{self.name}去捡{item}") + + def train(self, command): + """训练狗""" + print(f"正在训练{self.name}学习'{command}'命令") + self.is_trained = True + + def get_info(self): + """重写父类方法,添加狗特有信息""" + base_info = super().get_info() + breed_info = f",品种是{self.breed}" + owner_info = f",主人是{self.owner}" if self.owner else ",还没有主人" + training_info = f",{'已训练' if self.is_trained else '未训练'}" + return base_info + breed_info + owner_info + training_info + +class Cat(Animal): + """猫类 - 继承自Animal""" + + def __init__(self, name, breed, age, is_indoor=True): + super().__init__(name, "猫", age) + self.breed = breed + self.is_indoor = is_indoor + self.lives_remaining = 9 # 猫有九条命 + + def make_sound(self): + """重写父类方法 - 猫的叫声""" + print(f"{self.name}喵喵叫") + + def purr(self): + """猫特有的方法 - 呼噜声""" + print(f"{self.name}发出满足的呼噜声") + + def climb(self, target): + """猫特有的方法 - 爬高""" + print(f"{self.name}爬到了{target}上") + + def hunt(self, prey): + """猫特有的方法 - 狩猎""" + if not self.is_indoor: + print(f"{self.name}正在狩猎{prey}") + else: + print(f"{self.name}是室内猫,不能狩猎") + + def lose_life(self): + """失去一条命""" + if self.lives_remaining > 0: + self.lives_remaining -= 1 + print(f"{self.name}失去了一条命,还剩{self.lives_remaining}条命") + if self.lives_remaining == 0: + self.is_alive = False + print(f"{self.name}用完了所有的命") + else: + print(f"{self.name}已经没有命了") + +class Bird(Animal): + """鸟类 - 继承自Animal""" + + def __init__(self, name, species, age, can_fly=True): + super().__init__(name, species, age) + self.can_fly = can_fly + self.altitude = 0 # 当前高度 + + def make_sound(self): + """重写父类方法 - 鸟的叫声""" + print(f"{self.name}啾啾叫") + + def fly(self, height): + """鸟特有的方法 - 飞行""" + if self.can_fly: + self.altitude = height + print(f"{self.name}飞到了{height}米高") + else: + print(f"{self.name}不会飞") + + def land(self): + """降落""" + if self.altitude > 0: + print(f"{self.name}从{self.altitude}米高降落到地面") + self.altitude = 0 + else: + print(f"{self.name}已经在地面上了") + +# 使用示例 +print("=== 继承示例 ===") + +# 创建不同类型的动物 +dog = Dog("旺财", "金毛", 3, "张三") +cat = Cat("咪咪", "波斯猫", 2, True) +bird = Bird("小黄", "金丝雀", 1, True) + +animals = [dog, cat, bird] + +print("=== 所有动物的基本信息 ===") +for animal in animals: + print(animal.get_info()) + +print("\n=== 所有动物都会吃和睡 ===") +for animal in animals: + animal.eat("食物") + animal.sleep() + +print("\n=== 多态:不同动物发出不同声音 ===") +for animal in animals: + animal.make_sound() # 每个子类都有自己的实现 + +print("\n=== 各种动物的特有行为 ===") +# 狗的特有行为 +dog.wag_tail() +dog.fetch("球") +dog.train("坐下") + +# 猫的特有行为 +cat.purr() +cat.climb("书架") +cat.hunt("老鼠") +cat.lose_life() + +# 鸟的特有行为 +bird.fly(50) +bird.land() + +print("\n=== 检查继承关系 ===") +print(f"dog是Animal的实例吗?{isinstance(dog, Animal)}") +print(f"dog是Dog的实例吗?{isinstance(dog, Dog)}") +print(f"dog是Cat的实例吗?{isinstance(dog, Cat)}") +print(f"Dog是Animal的子类吗?{issubclass(Dog, Animal)}") +print(f"Animal是Dog的子类吗?{issubclass(Animal, Dog)}") +``` + +### 2.2 多重继承 + +```python +# 多重继承示例 +class Flyable: + """可飞行的混入类""" + + def __init__(self): + self.max_altitude = 1000 + self.current_altitude = 0 + + def take_off(self): + """起飞""" + if self.current_altitude == 0: + self.current_altitude = 10 + print(f"{self.name}起飞了,当前高度:{self.current_altitude}米") + else: + print(f"{self.name}已经在飞行中") + + def fly_to_altitude(self, altitude): + """飞到指定高度""" + if altitude <= self.max_altitude: + self.current_altitude = altitude + print(f"{self.name}飞到了{altitude}米高") + else: + print(f"{self.name}无法飞到{altitude}米,最大高度是{self.max_altitude}米") + + def land(self): + """降落""" + if self.current_altitude > 0: + print(f"{self.name}从{self.current_altitude}米高降落") + self.current_altitude = 0 + else: + print(f"{self.name}已经在地面上") + +class Swimmable: + """可游泳的混入类""" + + def __init__(self): + self.max_depth = 100 + self.current_depth = 0 + + def dive(self, depth): + """潜水""" + if depth <= self.max_depth: + self.current_depth = depth + print(f"{self.name}潜水到{depth}米深") + else: + print(f"{self.name}无法潜到{depth}米,最大深度是{self.max_depth}米") + + def surface(self): + """浮出水面""" + if self.current_depth > 0: + print(f"{self.name}从{self.current_depth}米深浮出水面") + self.current_depth = 0 + else: + print(f"{self.name}已经在水面上") + + def swim(self, direction): + """游泳""" + print(f"{self.name}向{direction}游泳") + +class Duck(Animal, Flyable, Swimmable): + """鸭子类 - 多重继承示例""" + + def __init__(self, name, age): + # 调用所有父类的构造方法 + Animal.__init__(self, name, "鸭子", age) + Flyable.__init__(self) + Swimmable.__init__(self) + + # 重新设置鸭子的特定限制 + self.max_altitude = 500 # 鸭子飞不太高 + self.max_depth = 5 # 鸭子潜不太深 + + def make_sound(self): + """重写父类方法 - 鸭子的叫声""" + print(f"{self.name}嘎嘎叫") + + def paddle(self): + """鸭子特有的方法 - 划水""" + print(f"{self.name}用脚掌划水") + +class Penguin(Animal, Swimmable): + """企鹅类 - 不会飞但会游泳""" + + def __init__(self, name, age): + Animal.__init__(self, name, "企鹅", age) + Swimmable.__init__(self) + self.max_depth = 200 # 企鹅游泳很厉害 + + def make_sound(self): + """企鹅的叫声""" + print(f"{self.name}发出企鹅特有的叫声") + + def slide_on_ice(self): + """在冰上滑行""" + print(f"{self.name}在冰上滑行") + +# 使用示例 +print("\n=== 多重继承示例 ===") + +duck = Duck("唐老鸭", 2) +penguin = Penguin("企鹅先生", 3) + +print("=== 鸭子的能力 ===") +print(duck.get_info()) +duck.make_sound() + +# 鸭子可以飞 +duck.take_off() +duck.fly_to_altitude(200) +duck.land() + +# 鸭子可以游泳 +duck.swim("前方") +duck.dive(3) +duck.paddle() +duck.surface() + +print("\n=== 企鹅的能力 ===") +print(penguin.get_info()) +penguin.make_sound() + +# 企鹅不能飞,但可以游泳 +penguin.swim("深海") +penguin.dive(50) +penguin.slide_on_ice() +penguin.surface() + +print("\n=== 方法解析顺序(MRO) ===") +print(f"Duck的MRO:{Duck.__mro__}") +print(f"Penguin的MRO:{Penguin.__mro__}") +``` + +--- + +## 三、多态 + +### 3.1 方法重写和多态 + +```python +# 多态示例:图形类 +class Shape: + """图形基类""" + + def __init__(self, name): + self.name = name + + def area(self): + """计算面积 - 基类中的抽象方法""" + raise NotImplementedError("子类必须实现area方法") + + def perimeter(self): + """计算周长 - 基类中的抽象方法""" + raise NotImplementedError("子类必须实现perimeter方法") + + def describe(self): + """描述图形""" + return f"这是一个{self.name},面积:{self.area():.2f},周长:{self.perimeter():.2f}" + + def __str__(self): + return f"{self.name}(面积: {self.area():.2f})" + +class Rectangle(Shape): + """矩形类""" + + def __init__(self, width, height): + super().__init__("矩形") + self.width = width + self.height = height + + def area(self): + """矩形面积""" + return self.width * self.height + + def perimeter(self): + """矩形周长""" + return 2 * (self.width + self.height) + + def is_square(self): + """判断是否为正方形""" + return self.width == self.height + +class Circle(Shape): + """圆形类""" + + def __init__(self, radius): + super().__init__("圆形") + self.radius = radius + + def area(self): + """圆形面积""" + import math + return math.pi * self.radius ** 2 + + def perimeter(self): + """圆形周长""" + import math + return 2 * math.pi * self.radius + + def diameter(self): + """直径""" + return 2 * self.radius + +class Triangle(Shape): + """三角形类""" + + def __init__(self, side1, side2, side3): + super().__init__("三角形") + self.side1 = side1 + self.side2 = side2 + self.side3 = side3 + + # 验证是否能构成三角形 + if not self._is_valid_triangle(): + raise ValueError("无效的三角形边长") + + def _is_valid_triangle(self): + """验证三角形的有效性""" + return (self.side1 + self.side2 > self.side3 and + self.side1 + self.side3 > self.side2 and + self.side2 + self.side3 > self.side1) + + def area(self): + """三角形面积(海伦公式)""" + s = self.perimeter() / 2 # 半周长 + import math + return math.sqrt(s * (s - self.side1) * (s - self.side2) * (s - self.side3)) + + def perimeter(self): + """三角形周长""" + return self.side1 + self.side2 + self.side3 + + def triangle_type(self): + """判断三角形类型""" + sides = sorted([self.side1, self.side2, self.side3]) + if sides[0] == sides[1] == sides[2]: + return "等边三角形" + elif sides[0] == sides[1] or sides[1] == sides[2]: + return "等腰三角形" + else: + return "普通三角形" + +# 多态函数 +def calculate_total_area(shapes): + """计算多个图形的总面积""" + total = 0 + for shape in shapes: + total += shape.area() # 多态:每个图形都有自己的area实现 + return total + +def print_shape_info(shapes): + """打印图形信息""" + for shape in shapes: + print(shape.describe()) # 多态:调用各自的area和perimeter方法 + +def find_largest_shape(shapes): + """找到面积最大的图形""" + if not shapes: + return None + return max(shapes, key=lambda shape: shape.area()) + +# 使用示例 +print("=== 多态示例 ===") + +# 创建不同类型的图形 +shapes = [ + Rectangle(5, 3), + Circle(4), + Triangle(3, 4, 5), + Rectangle(2, 2), # 正方形 + Circle(2.5) +] + +print("=== 所有图形信息 ===") +print_shape_info(shapes) + +print(f"\n=== 统计信息 ===") +print(f"图形总数:{len(shapes)}") +print(f"总面积:{calculate_total_area(shapes):.2f}") + +largest = find_largest_shape(shapes) +print(f"面积最大的图形:{largest}") + +print("\n=== 特定类型的操作 ===") +for shape in shapes: + if isinstance(shape, Rectangle): + if shape.is_square(): + print(f"{shape.name}是正方形,边长:{shape.width}") + else: + print(f"{shape.name}的长宽比:{shape.width/shape.height:.2f}") + elif isinstance(shape, Circle): + print(f"{shape.name}的直径:{shape.diameter():.2f}") + elif isinstance(shape, Triangle): + print(f"{shape.name}的类型:{shape.triangle_type()}") + +# 演示多态的威力 +print("\n=== 多态演示 ===") +def process_shape(shape): + """处理任意图形 - 不需要知道具体类型""" + print(f"处理{shape.name}:") + print(f" 面积: {shape.area():.2f}") + print(f" 周长: {shape.perimeter():.2f}") + + # 根据面积大小给出评价 + area = shape.area() + if area > 50: + print(" 这是一个大图形") + elif area > 20: + print(" 这是一个中等图形") + else: + print(" 这是一个小图形") + print() + +for shape in shapes: + process_shape(shape) # 同一个函数处理不同类型的图形 +``` + +### 3.2 抽象基类 + +```python +from abc import ABC, abstractmethod + +class Vehicle(ABC): + """交通工具抽象基类""" + + def __init__(self, brand, model, year): + self.brand = brand + self.model = model + self.year = year + self.is_running = False + + @abstractmethod + def start_engine(self): + """启动引擎 - 抽象方法""" + pass + + @abstractmethod + def stop_engine(self): + """停止引擎 - 抽象方法""" + pass + + @abstractmethod + def get_fuel_type(self): + """获取燃料类型 - 抽象方法""" + pass + + def get_info(self): + """获取车辆信息 - 具体方法""" + status = "运行中" if self.is_running else "停止" + return f"{self.year}年 {self.brand} {self.model},当前状态:{status}" + + def honk(self): + """鸣笛 - 具体方法""" + print(f"{self.brand} {self.model}鸣笛:嘀嘀!") + +class Car(Vehicle): + """汽车类""" + + def __init__(self, brand, model, year, doors=4): + super().__init__(brand, model, year) + self.doors = doors + self.fuel_level = 50 # 油量百分比 + + def start_engine(self): + """启动汽车引擎""" + if not self.is_running: + if self.fuel_level > 0: + self.is_running = True + print(f"{self.brand} {self.model}引擎启动成功") + else: + print(f"{self.brand} {self.model}没有燃料,无法启动") + else: + print(f"{self.brand} {self.model}引擎已经在运行") + + def stop_engine(self): + """停止汽车引擎""" + if self.is_running: + self.is_running = False + print(f"{self.brand} {self.model}引擎已停止") + else: + print(f"{self.brand} {self.model}引擎已经停止") + + def get_fuel_type(self): + """获取燃料类型""" + return "汽油" + + def refuel(self, amount): + """加油""" + self.fuel_level = min(100, self.fuel_level + amount) + print(f"{self.brand} {self.model}加油完成,当前油量:{self.fuel_level}%") + + def drive(self, distance): + """驾驶""" + if self.is_running: + fuel_consumed = distance * 0.1 # 假设每公里消耗0.1%的油 + if self.fuel_level >= fuel_consumed: + self.fuel_level -= fuel_consumed + print(f"{self.brand} {self.model}行驶了{distance}公里,剩余油量:{self.fuel_level:.1f}%") + else: + print(f"{self.brand} {self.model}燃料不足,无法行驶{distance}公里") + else: + print(f"{self.brand} {self.model}引擎未启动,无法行驶") + +class ElectricCar(Vehicle): + """电动汽车类""" + + def __init__(self, brand, model, year, battery_capacity=100): + super().__init__(brand, model, year) + self.battery_capacity = battery_capacity # 电池容量(kWh) + self.battery_level = 80 # 电量百分比 + + def start_engine(self): + """启动电动汽车""" + if not self.is_running: + if self.battery_level > 0: + self.is_running = True + print(f"{self.brand} {self.model}电动系统启动成功") + else: + print(f"{self.brand} {self.model}电池没电,无法启动") + else: + print(f"{self.brand} {self.model}电动系统已经在运行") + + def stop_engine(self): + """停止电动汽车""" + if self.is_running: + self.is_running = False + print(f"{self.brand} {self.model}电动系统已停止") + else: + print(f"{self.brand} {self.model}电动系统已经停止") + + def get_fuel_type(self): + """获取燃料类型""" + return "电力" + + def charge(self, hours): + """充电""" + charge_amount = hours * 10 # 假设每小时充电10% + self.battery_level = min(100, self.battery_level + charge_amount) + print(f"{self.brand} {self.model}充电{hours}小时,当前电量:{self.battery_level}%") + + def drive(self, distance): + """驾驶电动汽车""" + if self.is_running: + battery_consumed = distance * 0.2 # 假设每公里消耗0.2%的电 + if self.battery_level >= battery_consumed: + self.battery_level -= battery_consumed + print(f"{self.brand} {self.model}行驶了{distance}公里,剩余电量:{self.battery_level:.1f}%") + else: + print(f"{self.brand} {self.model}电量不足,无法行驶{distance}公里") + else: + print(f"{self.brand} {self.model}电动系统未启动,无法行驶") + +class Motorcycle(Vehicle): + """摩托车类""" + + def __init__(self, brand, model, year, engine_size): + super().__init__(brand, model, year) + self.engine_size = engine_size # 发动机排量 + self.fuel_level = 30 + + def start_engine(self): + """启动摩托车引擎""" + if not self.is_running: + if self.fuel_level > 0: + self.is_running = True + print(f"{self.brand} {self.model}摩托车引擎启动,轰鸣声响起") + else: + print(f"{self.brand} {self.model}没有燃料,无法启动") + else: + print(f"{self.brand} {self.model}引擎已经在运行") + + def stop_engine(self): + """停止摩托车引擎""" + if self.is_running: + self.is_running = False + print(f"{self.brand} {self.model}摩托车引擎已停止") + else: + print(f"{self.brand} {self.model}引擎已经停止") + + def get_fuel_type(self): + """获取燃料类型""" + return "汽油" + + def wheelie(self): + """摩托车特技 - 翘头""" + if self.is_running: + print(f"{self.brand} {self.model}做了一个精彩的翘头动作!") + else: + print(f"{self.brand} {self.model}需要先启动引擎") + +# 多态函数 +def start_all_vehicles(vehicles): + """启动所有车辆""" + print("=== 启动所有车辆 ===") + for vehicle in vehicles: + vehicle.start_engine() + +def show_vehicle_info(vehicles): + """显示所有车辆信息""" + print("=== 车辆信息 ===") + for vehicle in vehicles: + print(f"{vehicle.get_info()},燃料类型:{vehicle.get_fuel_type()}") + +def honk_all(vehicles): + """所有车辆鸣笛""" + print("=== 集体鸣笛 ===") + for vehicle in vehicles: + vehicle.honk() + +# 使用示例 +print("=== 抽象基类和多态示例 ===") + +# 创建不同类型的车辆 +vehicles = [ + Car("丰田", "卡罗拉", 2022), + ElectricCar("特斯拉", "Model 3", 2023, 75), + Motorcycle("本田", "CBR600RR", 2021, 600) +] + +# 显示车辆信息 +show_vehicle_info(vehicles) + +# 启动所有车辆 +start_all_vehicles(vehicles) + +# 集体鸣笛 +honk_all(vehicles) + +print("\n=== 特定操作 ===") +# 汽车加油和行驶 +car = vehicles[0] +car.refuel(20) +car.drive(50) + +# 电动汽车充电和行驶 +electric_car = vehicles[1] +electric_car.charge(2) +electric_car.drive(30) + +# 摩托车特技 +motorcycle = vehicles[2] +motorcycle.wheelie() + +# 尝试创建抽象基类的实例(会报错) +try: + abstract_vehicle = Vehicle("测试", "测试", 2023) +except TypeError as e: + print(f"\n无法创建抽象基类的实例:{e}") +``` + +--- + +## 四、特殊方法(魔术方法) + +### 4.1 常用特殊方法 + +```python +class Money: + """货币类 - 演示特殊方法的使用""" + + def __init__(self, amount, currency="CNY"): + self.amount = amount + self.currency = currency + + def __str__(self): + """用户友好的字符串表示""" + currency_symbols = { + "CNY": "¥", + "USD": "$", + "EUR": "€", + "JPY": "¥" + } + symbol = currency_symbols.get(self.currency, self.currency) + return f"{symbol}{self.amount:.2f}" + + def __repr__(self): + """开发者友好的字符串表示""" + return f"Money({self.amount}, '{self.currency}')" + + def __add__(self, other): + """加法运算""" + if isinstance(other, Money): + if self.currency == other.currency: + return Money(self.amount + other.amount, self.currency) + else: + raise ValueError(f"不能将{self.currency}和{other.currency}直接相加") + elif isinstance(other, (int, float)): + return Money(self.amount + other, self.currency) + else: + return NotImplemented + + def __radd__(self, other): + """右加法运算(当左操作数不支持加法时)""" + return self.__add__(other) + + def __sub__(self, other): + """减法运算""" + if isinstance(other, Money): + if self.currency == other.currency: + return Money(self.amount - other.amount, self.currency) + else: + raise ValueError(f"不能将{self.currency}和{other.currency}直接相减") + elif isinstance(other, (int, float)): + return Money(self.amount - other, self.currency) + else: + return NotImplemented + + def __mul__(self, other): + """乘法运算""" + if isinstance(other, (int, float)): + return Money(self.amount * other, self.currency) + else: + return NotImplemented + + def __rmul__(self, other): + """右乘法运算""" + return self.__mul__(other) + + def __truediv__(self, other): + """除法运算""" + if isinstance(other, (int, float)): + if other != 0: + return Money(self.amount / other, self.currency) + else: + raise ZeroDivisionError("不能除以零") + else: + return NotImplemented + + def __eq__(self, other): + """相等比较""" + if isinstance(other, Money): + return self.amount == other.amount and self.currency == other.currency + return False + + def __lt__(self, other): + """小于比较""" + if isinstance(other, Money): + if self.currency == other.currency: + return self.amount < other.amount + else: + raise ValueError(f"不能比较{self.currency}和{other.currency}") + return NotImplemented + + def __le__(self, other): + """小于等于比较""" + return self == other or self < other + + def __gt__(self, other): + """大于比较""" + if isinstance(other, Money): + if self.currency == other.currency: + return self.amount > other.amount + else: + raise ValueError(f"不能比较{self.currency}和{other.currency}") + return NotImplemented + + def __ge__(self, other): + """大于等于比较""" + return self == other or self > other + + def __hash__(self): + """哈希值(使对象可以用作字典键或集合元素)""" + return hash((self.amount, self.currency)) + + def __bool__(self): + """布尔值转换""" + return self.amount != 0 + + def __abs__(self): + """绝对值""" + return Money(abs(self.amount), self.currency) + + def __neg__(self): + """负数""" + return Money(-self.amount, self.currency) + + def __round__(self, ndigits=2): + """四舍五入""" + return Money(round(self.amount, ndigits), self.currency) + +class BankAccount: + """银行账户类 - 演示容器特殊方法""" + + def __init__(self, owner, initial_balance=0): + self.owner = owner + self.balance = Money(initial_balance) + self.transactions = [] # 交易记录 + + def deposit(self, amount): + """存款""" + if isinstance(amount, (int, float)): + amount = Money(amount) + self.balance += amount + self.transactions.append(f"存款 {amount}") + + def withdraw(self, amount): + """取款""" + if isinstance(amount, (int, float)): + amount = Money(amount) + if amount <= self.balance: + self.balance -= amount + self.transactions.append(f"取款 {amount}") + else: + raise ValueError("余额不足") + + def __len__(self): + """返回交易记录数量""" + return len(self.transactions) + + def __getitem__(self, index): + """通过索引获取交易记录""" + return self.transactions[index] + + def __setitem__(self, index, value): + """通过索引设置交易记录""" + self.transactions[index] = value + + def __delitem__(self, index): + """通过索引删除交易记录""" + del self.transactions[index] + + def __contains__(self, item): + """检查是否包含某个交易记录""" + return item in self.transactions + + def __iter__(self): + """使对象可迭代""" + return iter(self.transactions) + + def __str__(self): + return f"账户所有者:{self.owner},余额:{self.balance}" + + def __repr__(self): + return f"BankAccount('{self.owner}', {self.balance.amount})" + +# 使用示例 +print("=== 特殊方法示例 ===") + +# 创建货币对象 +money1 = Money(100, "CNY") +money2 = Money(50, "CNY") +money3 = Money(75, "USD") + +print("=== 基本操作 ===") +print(f"money1: {money1}") +print(f"money2: {money2}") +print(f"money3: {money3}") +print(f"repr(money1): {repr(money1)}") + +print("\n=== 算术运算 ===") +print(f"money1 + money2 = {money1 + money2}") +print(f"money1 - money2 = {money1 - money2}") +print(f"money1 * 2 = {money1 * 2}") +print(f"3 * money2 = {3 * money2}") +print(f"money1 / 4 = {money1 / 4}") +print(f"money1 + 25 = {money1 + 25}") + +print("\n=== 比较运算 ===") +print(f"money1 == money2: {money1 == money2}") +print(f"money1 > money2: {money1 > money2}") +print(f"money1 < money2: {money1 < money2}") + +print("\n=== 其他运算 ===") +print(f"abs(Money(-50)): {abs(Money(-50))}") +print(f"-money1: {-money1}") +print(f"round(Money(123.456)): {round(Money(123.456))}") +print(f"bool(Money(0)): {bool(Money(0))}") +print(f"bool(money1): {bool(money1)}") + +print("\n=== 银行账户示例 ===") +account = BankAccount("张三", 1000) +print(account) + +# 进行一些交易 +account.deposit(500) +account.withdraw(200) +account.deposit(Money(300)) + +print(f"\n交易记录数量:{len(account)}") +print("所有交易记录:") +for i, transaction in enumerate(account): + print(f"{i}: {transaction}") + +print(f"\n第一笔交易:{account[0]}") +print(f"最后一笔交易:{account[-1]}") +print(f"是否包含'存款 ¥500.00':{'存款 ¥500.00' in account}") + +# 货币对象可以用作字典键 +print("\n=== 货币作为字典键 ===") +portfolio = { + Money(1000, "CNY"): "人民币储蓄", + Money(500, "USD"): "美元投资", + Money(200, "EUR"): "欧元基金" +} + +for currency, description in portfolio.items(): + print(f"{currency}: {description}") + +# 尝试不同货币的运算(会报错) +try: + result = money1 + money3 # CNY + USD +except ValueError as e: + print(f"\n货币运算错误:{e}") +``` + +### 4.2 上下文管理器 + +```python +class FileManager: + """文件管理器 - 演示上下文管理器""" + + def __init__(self, filename, mode='r'): + self.filename = filename + self.mode = mode + self.file = None + + def __enter__(self): + """进入上下文时调用""" + print(f"打开文件:{self.filename}") + self.file = open(self.filename, self.mode) + return self.file + + def __exit__(self, exc_type, exc_value, traceback): + """退出上下文时调用""" + if self.file: + print(f"关闭文件:{self.filename}") + self.file.close() + + # 处理异常 + if exc_type is not None: + print(f"发生异常:{exc_type.__name__}: {exc_value}") + return False # 不抑制异常 + return True + +class DatabaseConnection: + """数据库连接 - 另一个上下文管理器示例""" + + def __init__(self, host, database): + self.host = host + self.database = database + self.connection = None + + def __enter__(self): + """建立数据库连接""" + print(f"连接到数据库:{self.host}/{self.database}") + # 这里模拟数据库连接 + self.connection = f"Connection to {self.database}" + return self.connection + + def __exit__(self, exc_type, exc_value, traceback): + """关闭数据库连接""" + if self.connection: + print(f"关闭数据库连接:{self.database}") + self.connection = None + return False + +# 使用示例 +print("\n=== 上下文管理器示例 ===") + +# 使用自定义文件管理器 +try: + with FileManager("test.txt", "w") as f: + f.write("Hello, World!") + f.write("\nPython面向对象编程") +except FileNotFoundError: + print("文件操作完成(文件可能不存在,这是正常的)") + +# 使用数据库连接管理器 +with DatabaseConnection("localhost", "myapp") as conn: + print(f"使用连接:{conn}") + # 模拟数据库操作 + print("执行SQL查询...") + +print("连接已自动关闭") +``` + +--- + +## 五、属性装饰器 + +### 5.1 @property装饰器 + +```python +class Temperature: + """温度类 - 演示属性装饰器的使用""" + + def __init__(self, celsius=0): + self._celsius = celsius + + @property + def celsius(self): + """获取摄氏温度""" + return self._celsius + + @celsius.setter + def celsius(self, value): + """设置摄氏温度""" + if value < -273.15: + raise ValueError("温度不能低于绝对零度(-273.15°C)") + self._celsius = value + + @property + def fahrenheit(self): + """获取华氏温度""" + return self._celsius * 9/5 + 32 + + @fahrenheit.setter + def fahrenheit(self, value): + """设置华氏温度""" + celsius = (value - 32) * 5/9 + if celsius < -273.15: + raise ValueError("温度不能低于绝对零度") + self._celsius = celsius + + @property + def kelvin(self): + """获取开尔文温度""" + return self._celsius + 273.15 + + @kelvin.setter + def kelvin(self, value): + """设置开尔文温度""" + if value < 0: + raise ValueError("开尔文温度不能为负数") + self._celsius = value - 273.15 + + def __str__(self): + return f"{self._celsius:.2f}°C ({self.fahrenheit:.2f}°F, {self.kelvin:.2f}K)" + +class Circle: + """圆形类 - 演示只读属性""" + + def __init__(self, radius): + self._radius = radius + + @property + def radius(self): + """半径(只读)""" + return self._radius + + @property + def diameter(self): + """直径(计算属性)""" + return self._radius * 2 + + @property + def area(self): + """面积(计算属性)""" + import math + return math.pi * self._radius ** 2 + + @property + def circumference(self): + """周长(计算属性)""" + import math + return 2 * math.pi * self._radius + + def __str__(self): + return f"圆形(半径: {self.radius}, 直径: {self.diameter:.2f}, 面积: {self.area:.2f}, 周长: {self.circumference:.2f})" + +class Person: + """人员类 - 演示属性验证""" + + def __init__(self, name, age, email): + self.name = name + self.age = age + self.email = email + + @property + def name(self): + return self._name + + @name.setter + def name(self, value): + if not isinstance(value, str) or len(value.strip()) == 0: + raise ValueError("姓名必须是非空字符串") + self._name = value.strip() + + @property + def age(self): + return self._age + + @age.setter + def age(self, value): + if not isinstance(value, int) or value < 0 or value > 150: + raise ValueError("年龄必须是0-150之间的整数") + self._age = value + + @property + def email(self): + return self._email + + @email.setter + def email(self, value): + if not isinstance(value, str) or '@' not in value: + raise ValueError("邮箱格式不正确") + self._email = value.lower() + + @property + def is_adult(self): + """是否成年(只读属性)""" + return self._age >= 18 + + @property + def age_group(self): + """年龄组(只读属性)""" + if self._age < 13: + return "儿童" + elif self._age < 18: + return "青少年" + elif self._age < 60: + return "成年人" + else: + return "老年人" + + def __str__(self): + return f"{self.name}({self.age}岁, {self.email}, {self.age_group})" + +# 使用示例 +print("=== 属性装饰器示例 ===") + +# 温度转换 +print("=== 温度转换 ===") +temp = Temperature(25) +print(f"初始温度:{temp}") + +# 设置不同单位的温度 +temp.fahrenheit = 100 +print(f"设置华氏100度后:{temp}") + +temp.kelvin = 300 +print(f"设置开尔文300度后:{temp}") + +# 尝试设置无效温度 +try: + temp.celsius = -300 +except ValueError as e: + print(f"温度设置错误:{e}") + +# 圆形计算属性 +print("\n=== 圆形计算属性 ===") +circle = Circle(5) +print(circle) + +# 人员属性验证 +print("\n=== 人员属性验证 ===") +try: + person = Person("张三", 25, "zhangsan@example.com") + print(person) + print(f"是否成年:{person.is_adult}") + + # 修改属性 + person.age = 17 + print(f"修改年龄后:{person}") + print(f"是否成年:{person.is_adult}") + + # 尝试设置无效邮箱 + person.email = "invalid-email" +except ValueError as e: + print(f"属性设置错误:{e}") +``` + +--- + +## 六、实战练习 + +### 6.1 图书管理系统 + +```python +from datetime import datetime, timedelta + +class Book: + """图书类""" + + def __init__(self, isbn, title, author, publisher, price, total_copies=1): + self.isbn = isbn + self.title = title + self.author = author + self.publisher = publisher + self.price = price + self.total_copies = total_copies + self.available_copies = total_copies + self.borrowed_copies = 0 + + def borrow(self): + """借书""" + if self.available_copies > 0: + self.available_copies -= 1 + self.borrowed_copies += 1 + return True + return False + + def return_book(self): + """还书""" + if self.borrowed_copies > 0: + self.available_copies += 1 + self.borrowed_copies -= 1 + return True + return False + + @property + def is_available(self): + """是否有可借阅的副本""" + return self.available_copies > 0 + + def __str__(self): + return f"《{self.title}》- {self.author} (可借: {self.available_copies}/{self.total_copies})" + + def __repr__(self): + return f"Book('{self.isbn}', '{self.title}', '{self.author}')" + +class Member: + """会员类""" + + def __init__(self, member_id, name, phone, email): + self.member_id = member_id + self.name = name + self.phone = phone + self.email = email + self.borrowed_books = [] # 当前借阅的书籍 + self.borrow_history = [] # 借阅历史 + self.join_date = datetime.now() + + def can_borrow(self, max_books=5): + """检查是否可以借书""" + return len(self.borrowed_books) < max_books + + def borrow_book(self, book, due_days=30): + """借书""" + if not self.can_borrow(): + return False, "已达到最大借书数量" + + if not book.is_available: + return False, "图书不可借阅" + + if book.borrow(): + borrow_record = { + 'book': book, + 'borrow_date': datetime.now(), + 'due_date': datetime.now() + timedelta(days=due_days), + 'returned': False + } + self.borrowed_books.append(borrow_record) + self.borrow_history.append(borrow_record) + return True, "借书成功" + + return False, "借书失败" + + def return_book(self, book): + """还书""" + for record in self.borrowed_books: + if record['book'] == book and not record['returned']: + record['returned'] = True + record['return_date'] = datetime.now() + self.borrowed_books.remove(record) + book.return_book() + return True, "还书成功" + + return False, "未找到借阅记录" + + def get_overdue_books(self): + """获取逾期图书""" + overdue = [] + current_time = datetime.now() + for record in self.borrowed_books: + if current_time > record['due_date']: + overdue.append(record) + return overdue + + def __str__(self): + return f"会员: {self.name} (ID: {self.member_id}, 当前借阅: {len(self.borrowed_books)}本)" + +class Library: + """图书馆类""" + + def __init__(self, name): + self.name = name + self.books = {} # ISBN -> Book + self.members = {} # member_id -> Member + self.next_member_id = 1 + + def add_book(self, book): + """添加图书""" + if book.isbn in self.books: + # 如果图书已存在,增加副本数 + existing_book = self.books[book.isbn] + existing_book.total_copies += book.total_copies + existing_book.available_copies += book.available_copies + else: + self.books[book.isbn] = book + print(f"添加图书成功:{book}") + + def register_member(self, name, phone, email): + """注册会员""" + member_id = f"M{self.next_member_id:04d}" + member = Member(member_id, name, phone, email) + self.members[member_id] = member + self.next_member_id += 1 + print(f"会员注册成功:{member}") + return member + + def search_books(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.publisher.lower()): + results.append(book) + return results + + def borrow_book(self, member_id, isbn): + """借书""" + if member_id not in self.members: + return False, "会员不存在" + + if isbn not in self.books: + return False, "图书不存在" + + member = self.members[member_id] + book = self.books[isbn] + + return member.borrow_book(book) + + def return_book(self, member_id, isbn): + """还书""" + if member_id not in self.members: + return False, "会员不存在" + + if isbn not in self.books: + return False, "图书不存在" + + member = self.members[member_id] + book = self.books[isbn] + + return member.return_book(book) + + def get_overdue_report(self): + """获取逾期报告""" + overdue_info = [] + for member in self.members.values(): + overdue_books = member.get_overdue_books() + if overdue_books: + overdue_info.append((member, overdue_books)) + return overdue_info + + def get_statistics(self): + """获取统计信息""" + total_books = sum(book.total_copies for book in self.books.values()) + available_books = sum(book.available_copies for book in self.books.values()) + borrowed_books = total_books - available_books + + return { + 'total_books': total_books, + 'available_books': available_books, + 'borrowed_books': borrowed_books, + 'total_members': len(self.members), + 'unique_titles': len(self.books) + } + + def __str__(self): + stats = self.get_statistics() + return f"{self.name} - 图书: {stats['unique_titles']}种/{stats['total_books']}本, 会员: {stats['total_members']}人" + +# 使用示例 +print("\n=== 图书管理系统示例 ===") + +# 创建图书馆 +library = Library("Python学习图书馆") + +# 添加图书 +books_data = [ + ("978-0-123456-78-9", "Python编程:从入门到实践", "埃里克·马瑟斯", "人民邮电出版社", 89.0, 3), + ("978-0-987654-32-1", "流畅的Python", "Luciano Ramalho", "O'Reilly", 139.0, 2), + ("978-0-111111-11-1", "Python核心编程", "Wesley Chun", "机械工业出版社", 99.0, 2), + ("978-0-222222-22-2", "Python数据分析", "Wes McKinney", "机械工业出版社", 119.0, 1) +] + +for isbn, title, author, publisher, price, copies in books_data: + book = Book(isbn, title, author, publisher, price, copies) + library.add_book(book) + +print(f"\n{library}") + +# 注册会员 +members = [ + library.register_member("张三", "13800138001", "zhangsan@example.com"), + library.register_member("李四", "13800138002", "lisi@example.com"), + library.register_member("王五", "13800138003", "wangwu@example.com") +] + +# 搜索图书 +print("\n=== 搜索图书 ===") +search_results = library.search_books("Python") +print(f"搜索'Python'的结果:") +for book in search_results: + print(f" {book}") + +# 借书操作 +print("\n=== 借书操作 ===") +borrow_operations = [ + ("M0001", "978-0-123456-78-9"), + ("M0001", "978-0-987654-32-1"), + ("M0002", "978-0-123456-78-9"), + ("M0003", "978-0-111111-11-1") +] + +for member_id, isbn in borrow_operations: + success, message = library.borrow_book(member_id, isbn) + member_name = library.members[member_id].name + book_title = library.books[isbn].title + print(f"{member_name} 借阅《{book_title}》: {message}") + +# 显示会员借阅情况 +print("\n=== 会员借阅情况 ===") +for member in library.members.values(): + print(member) + for record in member.borrowed_books: + book = record['book'] + due_date = record['due_date'].strftime('%Y-%m-%d') + print(f" - 《{book.title}》(到期日: {due_date})") + +# 还书操作 +print("\n=== 还书操作 ===") +success, message = library.return_book("M0001", "978-0-123456-78-9") +print(f"张三 归还《Python编程:从入门到实践》: {message}") + +# 显示统计信息 +print("\n=== 图书馆统计 ===") +stats = library.get_statistics() +for key, value in stats.items(): + print(f"{key}: {value}") +``` + +--- + +## 七、总结 + +### 面向对象编程核心概念回顾 + +1. **类和对象** + - 类是对象的模板,对象是类的实例 + - 使用`__init__`方法初始化对象 + - 类变量和实例变量的区别 + +2. **封装** + - 使用私有属性(`__attribute`)隐藏内部实现 + - 使用属性装饰器(`@property`)控制属性访问 + - 提供公共接口操作私有数据 + +3. **继承** + - 子类继承父类的属性和方法 + - 使用`super()`调用父类方法 + - 方法重写实现多态 + - 多重继承和MRO(方法解析顺序) + +4. **多态** + - 同一接口,不同实现 + - 抽象基类定义接口规范 + - 运行时确定调用哪个方法 + +5. **特殊方法** + - 定制对象行为(`__str__`, `__repr__`等) + - 运算符重载(`__add__`, `__eq__`等) + - 上下文管理器(`__enter__`, `__exit__`) + +### 最佳实践 + +1. **设计原则** + - 单一职责:每个类只负责一个功能 + - 开闭原则:对扩展开放,对修改关闭 + - 里氏替换:子类可以替换父类 + - 依赖倒置:依赖抽象而不是具体实现 + +2. **命名规范** + - 类名使用大驼峰命名(PascalCase) + - 方法和属性使用小写加下划线(snake_case) + - 私有属性使用双下划线前缀 + - 常量使用全大写加下划线 + +3. **文档和测试** + - 为类和方法编写清晰的文档字符串 + - 使用类型注解提高代码可读性 + - 编写单元测试验证功能正确性 + +### 下一步学习方向 + +1. **设计模式** + - 单例模式、工厂模式、观察者模式等 + - 学习如何解决常见的设计问题 + +2. **高级特性** + - 元类(metaclass) + - 描述符(descriptor) + - 装饰器的高级用法 + +3. **实际应用** + - Web开发中的OOP应用 + - 数据库ORM的设计 + - GUI编程中的事件驱动 + +### 练习建议 + +1. **基础练习** + - 设计一个学生成绩管理系统 + - 实现一个简单的银行账户系统 + - 创建一个动物园管理系统 + +2. **进阶练习** + - 设计一个电商购物车系统 + - 实现一个简单的游戏角色系统 + - 创建一个文件管理器 + +3. **项目实战** + - 开发一个完整的图书管理系统 + - 实现一个简单的博客系统 + - 创建一个任务管理应用 + +面向对象编程是Python中非常重要的编程范式,掌握好OOP的概念和技巧,将为你后续学习更高级的Python特性和框架打下坚实的基础。记住,最好的学习方法就是多练习、多实践! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Python/img.png b/docs/Python/img.png new file mode 100644 index 000000000..2916942eb Binary files /dev/null and b/docs/Python/img.png differ diff --git a/docs/Python/img_1.png b/docs/Python/img_1.png new file mode 100644 index 000000000..b00c0bf5c Binary files /dev/null and b/docs/Python/img_1.png differ diff --git a/docs/Python/img_2.png b/docs/Python/img_2.png new file mode 100644 index 000000000..042200f5d Binary files /dev/null and b/docs/Python/img_2.png differ diff --git a/docs/Python/img_3.png b/docs/Python/img_3.png new file mode 100644 index 000000000..901429aa8 Binary files /dev/null and b/docs/Python/img_3.png differ diff --git a/docs/README.md b/docs/README.md index 3f20a5b48..869918f12 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,154 +1,434 @@ -> 点击勘误[issues](https://github.com/webVueBlog/JavaPlusDoc/issues),哪吒感谢大家的阅读 +# JavaPlus 技术文档平台 -## 感谢关注 Thanks for your attention ༼ つ ◕_◕ ༽つ
+本平台是一个战略性的Java技术知识体系,构建了从基础到高级的微服务分布式系统完整架构图谱。平台采用企业级文档标准,支持全文检索、多端适配,为组织内不同层级的技术人员(初学者、中级开发者、高级架构师、技术决策者)提供系统化的技术参考和能力提升路径。
+**平台价值**:提升团队技术能力,加速项目交付,降低技术决策风险,支持业务创新
-如果您觉得本文档对您的学习和工作有所帮助,欢迎扫描下方二维码进行打赏支持。您的每一份鼓励都是我们持续创作优质内容的动力!
+
+ 感谢您的支持与鼓励!
+您的赞助将用于平台维护、内容更新与技术研究
+
+- **技术能力建设**:系统化培养团队从初级到高级的技术梯队,支撑业务持续发展
+- **降低技术风险**:提供经过验证的架构方案和最佳实践,减少技术决策失误
+- **加速项目交付**:通过标准化技术方案和组件复用,显著提高研发效率
+- **促进技术创新**:整合行业前沿技术,为业务创新提供技术支撑
+- **知识资产沉淀**:将团队核心技术经验转化为可持续的组织知识资产
+## 核心技术体系
-#### 后端技术栈
+### 后端技术架构
-+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+企业可以基于本平台进行定制化扩展:
-## 感谢指正
+- **行业特化**:增加特定行业的技术应用案例
+- **企业实践**:整合企业内部最佳实践和技术标准
+- **团队培训**:定制化的培训课程和学习路径
+- **评估体系**:与企业人才评估体系对接
-指正不胜感激,无以回报。
+欢迎通过[Issues](https://github.com/webVueBlog/JavaPlusDoc/issues)提交反馈和建议,帮助我们持续提升平台价值。
-## 声明
+### 技术理念
-文档仅适合本人食用!!!
+> 进一寸有一寸的欣喜 —— 持续学习,每天进步一点点!
-
+作者致力于技术的学习与分享,通过开源项目和技术文章帮助更多开发者成长。欢迎通过GitHub、掘金等与作者交流,共同进步!
diff --git "a/docs/aJava/Ansible\346\230\257\344\273\200\344\271\210.md" "b/docs/aJava/Ansible\346\230\257\344\273\200\344\271\210.md"
new file mode 100644
index 000000000..484dbf121
--- /dev/null
+++ "b/docs/aJava/Ansible\346\230\257\344\273\200\344\271\210.md"
@@ -0,0 +1,9 @@
+# Ansible是什么
+
+Ansible是什么, 自动化运维
+
+能让你用一句话控制成百上千台服务器
+
+底层靠SSH协议通信,Yaml语言写“剧本”,把复杂操作变成可重复的代码。核心技术叫“幂等性”,同一个任务重复执行。结果永远一致,比如批量安装软件。
+
+Ansible会自动检测是否装过,避免重复劳动,批量部署,自动化运维,紧急修复漏洞,关键组件:Inventory定义服务器清单,modules是现成的功能模块。Playbook是任务剧本,roles是模块化角色集合。
\ No newline at end of file
diff --git "a/docs/aJava/CDN\346\230\257\344\273\200\344\271\210.md" "b/docs/aJava/CDN\346\230\257\344\273\200\344\271\210.md"
new file mode 100644
index 000000000..a64d8f457
--- /dev/null
+++ "b/docs/aJava/CDN\346\230\257\344\273\200\344\271\210.md"
@@ -0,0 +1,26 @@
+# CDN是什么
+
+CDN即内容分发网络,本质上是个“内容快递网络”,是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。
+
+CDN,它把源站的数据提前缓存到离用户最近的节点,用空间换时间,用分布抗压力,文本数据用关系型数据库+Redis的组合拳,文件数据就要用对象存储+CDN的组合拳。就像select * from user where id = 1,我们可以用redis缓存,而不用每次去后端查询数据库。从而减少了源库的压力。
+
+为什么redis不能存储图片呢?想象一下10GB的Redis实例存10万张图,光是维护key列表就能让内容爆炸,而CDN的边缘节点自带硬盘存储,专门为海量文件而设计,CDN架构:
+
+1. 第一层调度系统,像导航地图,用DNS解析+IP定位,把用户定位到离他最近的节点。
+2. 边缘节点,相当于遍历全国的快递网点,用SSD硬盘+内存缓存高频内容。最近用过的资源优先保留。
+3. 第三层回源机制,当本地也没存货时,用HTTP/2快速从源站拉数据,还能自动平衡多个源站压力
+
+CDN实际解决问题:输入网址,首先电脑会根据访问的域名查看浏览器缓存;再看操作系统缓 名的解析,这时云厂商的DNS调度系统,根据你的IP+运营商+节点负载,动态分配“最近最优”的CDN服务器IP给你访问,这个IP其实就是个CDN边缘节点IP。只是这个节点离你最近,访问比较快而已。
+
+当你第一次访问时,边缘节点会检查缓存版本,如果有存货且未过期,直接这个节点给你闪电响应;如果过期了,就秒回源站拿最新版本,同时更新本地库存。
+
+预热办法:上线前,用curl命令去提前访问,并把热数据灌满CDN节点,避免大批流量访问。
+
+场景使用:
+
+1. 全球用户访问的网站,跨境电商
+2. 突发流量场景(新品发布,抽奖活动)
+3. 大文件分发(游戏更新包,4K视频)
+4. 需要隐藏源站IP的敏感业务
+
+因为redis的存储是基于内存的,内存是有限的,而图片是基于磁盘的,磁盘是无限的。所以redis不能存储图片。
diff --git "a/docs/aJava/ClickHouse\345\210\206\347\211\207\346\212\200\346\234\257\345\256\236\347\216\260.md" "b/docs/aJava/ClickHouse\345\210\206\347\211\207\346\212\200\346\234\257\345\256\236\347\216\260.md"
new file mode 100644
index 000000000..58777f709
--- /dev/null
+++ "b/docs/aJava/ClickHouse\345\210\206\347\211\207\346\212\200\346\234\257\345\256\236\347\216\260.md"
@@ -0,0 +1,1498 @@
+# ClickHouse分片技术实现
+
+## 概述
+
+ClickHouse是一个用于在线分析处理(OLAP)的列式数据库管理系统,具有极高的查询性能。ClickHouse的分片机制通过分布式表和本地表的组合实现水平扩展,支持PB级数据的实时分析。
+
+## ClickHouse架构
+
+### 核心概念
+
+- **Shard**: 数据分片,每个分片包含部分数据
+- **Replica**: 副本,提供数据冗余和高可用
+- **Distributed Table**: 分布式表,查询入口
+- **Local Table**: 本地表,实际存储数据
+- **ZooKeeper**: 协调服务,管理副本同步
+
+### 分片架构图
+
+```
+分布式表 (Distributed)
+├── Shard 1
+│ ├── Replica 1 (本地表)
+│ └── Replica 2 (本地表)
+├── Shard 2
+│ ├── Replica 1 (本地表)
+│ └── Replica 2 (本地表)
+└── Shard N
+ ├── Replica 1 (本地表)
+ └── Replica 2 (本地表)
+```
+
+## 环境搭建
+
+### Docker Compose配置
+
+```yaml
+version: '3.8'
+services:
+ zookeeper:
+ image: zookeeper:3.7
+ container_name: clickhouse-zookeeper
+ ports:
+ - "2181:2181"
+ environment:
+ ZOO_MY_ID: 1
+ ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181
+ volumes:
+ - zk_data:/data
+ - zk_logs:/datalog
+
+ clickhouse-01:
+ image: clickhouse/clickhouse-server:23.8
+ container_name: clickhouse-01
+ hostname: clickhouse-01
+ ports:
+ - "8123:8123" # HTTP接口
+ - "9000:9000" # Native接口
+ volumes:
+ - ./config/clickhouse-01:/etc/clickhouse-server
+ - ch01_data:/var/lib/clickhouse
+ - ch01_logs:/var/log/clickhouse-server
+ depends_on:
+ - zookeeper
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+
+ clickhouse-02:
+ image: clickhouse/clickhouse-server:23.8
+ container_name: clickhouse-02
+ hostname: clickhouse-02
+ ports:
+ - "8124:8123" # HTTP接口
+ - "9001:9000" # Native接口
+ volumes:
+ - ./config/clickhouse-02:/etc/clickhouse-server
+ - ch02_data:/var/lib/clickhouse
+ - ch02_logs:/var/log/clickhouse-server
+ depends_on:
+ - zookeeper
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+
+ clickhouse-03:
+ image: clickhouse/clickhouse-server:23.8
+ container_name: clickhouse-03
+ hostname: clickhouse-03
+ ports:
+ - "8125:8123" # HTTP接口
+ - "9002:9000" # Native接口
+ volumes:
+ - ./config/clickhouse-03:/etc/clickhouse-server
+ - ch03_data:/var/lib/clickhouse
+ - ch03_logs:/var/log/clickhouse-server
+ depends_on:
+ - zookeeper
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+
+ clickhouse-04:
+ image: clickhouse/clickhouse-server:23.8
+ container_name: clickhouse-04
+ hostname: clickhouse-04
+ ports:
+ - "8126:8123" # HTTP接口
+ - "9003:9000" # Native接口
+ volumes:
+ - ./config/clickhouse-04:/etc/clickhouse-server
+ - ch04_data:/var/lib/clickhouse
+ - ch04_logs:/var/log/clickhouse-server
+ depends_on:
+ - zookeeper
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+
+volumes:
+ zk_data:
+ zk_logs:
+ ch01_data:
+ ch01_logs:
+ ch02_data:
+ ch02_logs:
+ ch03_data:
+ ch03_logs:
+ ch04_data:
+ ch04_logs:
+```
+
+### ClickHouse配置文件
+
+#### config/clickhouse-01/config.xml
+
+```xml
+
+