Python入门(10)--面向对象进阶

Python面向对象进阶 🚀

1. 继承与多态 🔄

1.1 继承基础

class Animal:def __init__(self, name, age):self.name = nameself.age = agedef speak(self):passdef describe(self):return f"{self.name} is {self.age} years old"class Dog(Animal):def __init__(self, name, age, breed):super().__init__(name, age)  # 调用父类的初始化方法self.breed = breeddef speak(self):return f"{self.name} says Woof!"def describe(self):# 扩展父类的方法return f"{super().describe()} and is a {self.breed}"class Cat(Animal):def __init__(self, name, age, indoor=True):super().__init__(name, age)self.indoor = indoordef speak(self):return f"{self.name} says Meow!"def describe(self):habitat = "indoor" if self.indoor else "outdoor"return f"{super().describe()} and is an {habitat} cat"# 使用示例
dog = Dog("Buddy", 3, "Golden Retriever")
cat = Cat("Whiskers", 2, True)print(dog.describe())  # 输出: Buddy is 3 years old and is a Golden Retriever
print(cat.describe())  # 输出: Whiskers is 2 years old and is an indoor cat

继承的关键概念:

  1. super()的使用:调用父类方法
  2. 方法重写与扩展
  3. 构造函数的继承与扩展
  4. 属性的继承与新增

1.2 多态

让我们通过一个更实际的例子来展示多态的威力:

class Document:def __init__(self, content):self.content = contentdef format(self):passclass PlainText(Document):def format(self):return self.contentclass HTMLDocument(Document):def format(self):return f"<html><body>{self.content}</body></html>"class MarkdownDocument(Document):def format(self):return f"# {self.content}"def process_documents(documents):"""多态函数 - 统一处理不同类型的文档"""for doc in documents:print(f"处理 {doc.__class__.__name__}:")print(doc.format())print("---")# 实际应用
documents = [PlainText("Hello World"),HTMLDocument("Welcome"),MarkdownDocument("Title")
]process_documents(documents)

1.3 多重继承

让我们通过一个更实用的场景来展示多重继承:

class Persistable:"""提供持久化功能的混入类"""def save(self, filename):with open(filename, 'w') as f:f.write(str(self.__dict__))def load(self, filename):with open(filename, 'r') as f:data = eval(f.read())self.__dict__.update(data)class Loggable:"""提供日志功能的混入类"""def log(self, message):print(f"[{self.__class__.__name__}] {message}")class Configuration(Persistable, Loggable):"""应用配置类"""def __init__(self, host="localhost", port=8000):self.host = hostself.port = portdef update_config(self, **kwargs):self.log("Updating configuration...")self.__dict__.update(kwargs)self.log("Configuration updated")# 使用示例
config = Configuration()
config.update_config(host="127.0.0.1", port=5000)
config.save("config.txt")  # 保存配置
config.load("config.txt")  # 加载配置

2. 封装与访问控制 🔒

让我们通过一个更完整的例子来展示Python的封装机制:

class Employee:def __init__(self, name, salary):self._name = name            # 受保护的属性self.__salary = salary       # 私有属性self.__bonus = 0             # 私有属性@propertydef name(self):"""只读属性"""return self._name@propertydef total_salary(self):"""计算总薪资(基本工资 + 奖金)"""return self.__salary + self.__bonus@propertydef bonus(self):"""奖金查询"""return self.__bonus@bonus.setterdef bonus(self, value):"""设置奖金,带验证"""if not isinstance(value, (int, float)):raise TypeError("奖金必须是数字")if value < 0:raise ValueError("奖金不能为负数")self.__bonus = valuedef _calculate_tax(self):"""受保护的方法 - 计算税收"""return self.total_salary * 0.2def get_salary_info(self):"""公开方法 - 获取薪资信息"""return {'name': self._name,'total_salary': self.total_salary,'tax': self._calculate_tax(),'net_salary': self.total_salary - self._calculate_tax()}# 使用示例
emp = Employee("John Doe", 5000)# 属性访问
print(emp.name)         # 使用@property
emp.bonus = 1000        # 使用@bonus.setter
print(emp.total_salary) # 使用@property计算总薪资# 获取完整信息
salary_info = emp.get_salary_info()
for key, value in salary_info.items():print(f"{key}: {value}")# 以下操作会引发错误
# emp.name = "Jane"     # AttributeError: 不能修改只读属性
# emp.__salary = 6000   # AttributeError: 私有属性不能直接访问
# emp.bonus = -100      # ValueError: 奖金不能为负数

补充说明:

  1. 使用@property创建只读属性
  2. 使用@property@x.setter创建可读写属性
  3. 使用单下划线表示受保护成员
  4. 使用双下划线表示私有成员
  5. 通过公开方法提供对私有数据的安全访问

3. 类方法与静态方法 🛠️

3.1 类方法(@classmethod)

让我们通过一个更实用的工厂模式示例来展示类方法的应用:

from datetime import datetime, dateclass Order:"""订单类"""order_count = 0  # 类变量,用于追踪订单数量def __init__(self, customer_id: str, items: list, order_date: date):Order.order_count += 1self.order_id = f"ORD{Order.order_count:04d}"self.customer_id = customer_idself.items = itemsself.order_date = order_dateself.status = "pending"@classmethoddef create_from_dict(cls, order_data: dict):"""从字典创建订单对象"""try:customer_id = order_data['customer_id']items = order_data['items']# 解析日期字符串date_str = order_data.get('date', datetime.now().strftime('%Y-%m-%d'))order_date = datetime.strptime(date_str, '%Y-%m-%d').date()return cls(customer_id, items, order_date)except KeyError as e:raise ValueError(f"缺少必要的订单信息: {e}")@classmethoddef create_rush_order(cls, customer_id: str, items: list):"""创建加急订单"""order = cls(customer_id, items, date.today())order.status = "rush"return order@classmethoddef get_order_count(cls) -> int:"""获取订单总数"""return cls.order_countdef __str__(self):return f"Order {self.order_id}: {len(self.items)} items for {self.customer_id}"# 使用示例
# 1. 常规创建
order1 = Order("CUST001", ["item1", "item2"], date.today())# 2. 从字典创建
order_data = {"customer_id": "CUST002","items": ["item3", "item4"],"date": "2024-03-15"
}
order2 = Order.create_from_dict(order_data)# 3. 创建加急订单
rush_order = Order.create_rush_order("CUST003", ["urgent_item"])print(f"Total orders: {Order.get_order_count()}")  # 输出订单总数

3.2 静态方法(@staticmethod)

通过一个更复杂的示例来展示静态方法的实际应用:

class DataValidator:"""数据验证工具类"""@staticmethoddef validate_email(email: str) -> bool:"""验证邮箱格式"""import repattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'return bool(re.match(pattern, email))@staticmethoddef validate_phone(phone: str) -> bool:"""验证电话号码格式"""import re# 支持多种格式:+86-123-4567-8901, 12345678901, 123-4567-8901patterns = [r'^\+\d{1,3}-\d{3}-\d{4}-\d{4}$',r'^\d{11}$',r'^\d{3}-\d{4}-\d{4}$']return any(bool(re.match(pattern, phone)) for pattern in patterns)@staticmethoddef validate_date(date_str: str) -> bool:"""验证日期格式和有效性"""try:datetime.strptime(date_str, '%Y-%m-%d')return Trueexcept ValueError:return False@staticmethoddef sanitize_string(text: str) -> str:"""清理并验证字符串"""# 移除首尾空白,替换多个空格为单个空格text = ' '.join(text.split())# 移除特殊字符text = ''.join(char for char in text if char.isprintable())return textclass UserProfile:"""用户档案类 - 展示数据验证的应用"""def __init__(self, email: str, phone: str, birth_date: str):if not DataValidator.validate_email(email):raise ValueError("无效的邮箱地址")if not DataValidator.validate_phone(phone):raise ValueError("无效的电话号码")if not DataValidator.validate_date(birth_date):raise ValueError("无效的出生日期")self.email = emailself.phone = phoneself.birth_date = birth_date# 使用示例
try:# 创建用户档案user = UserProfile(email="john.doe@example.com",phone="123-4567-8901",birth_date="1990-01-01")print("用户档案创建成功")# 验证和清理数据text = "   Hello   World!   \n\t@#$%   "cleaned = DataValidator.sanitize_string(text)print(f"清理后的文本: '{cleaned}'")except ValueError as e:print(f"错误: {e}")

4. 抽象类与接口 🎯

让我们通过一个文件处理系统的例子来展示抽象类和接口的实际应用:

from abc import ABC, abstractmethod
from typing import Any, List, Dict
import json
import csv
import xml.etree.ElementTree as ETclass DataProcessor(ABC):"""数据处理器抽象基类"""@abstractmethoddef read(self, source: str) -> Any:"""读取数据"""pass@abstractmethoddef write(self, data: Any, destination: str) -> bool:"""写入数据"""pass@abstractmethoddef validate(self, data: Any) -> bool:"""验证数据"""pass@property@abstractmethoddef supported_extensions(self) -> List[str]:"""支持的文件扩展名"""passclass JSONProcessor(DataProcessor):"""JSON数据处理器"""@propertydef supported_extensions(self) -> List[str]:return ['.json']def validate(self, data: Any) -> bool:if not isinstance(data, (dict, list)):return Falsetry:json.dumps(data)  # 测试是否可序列化return Trueexcept (TypeError, ValueError):return Falsedef read(self, source: str) -> Any:try:with open(source, 'r', encoding='utf-8') as f:return json.load(f)except json.JSONDecodeError as e:raise ValueError(f"JSON解析错误: {e}")def write(self, data: Any, destination: str) -> bool:if not self.validate(data):raise ValueError("无效的JSON数据")try:with open(destination, 'w', encoding='utf-8') as f:json.dump(data, f, indent=2, ensure_ascii=False)return Trueexcept Exception as e:print(f"写入错误: {e}")return Falseclass CSVProcessor(DataProcessor):"""CSV数据处理器"""@propertydef supported_extensions(self) -> List[str]:return ['.csv']def validate(self, data: Any) -> bool:return isinstance(data, list) and all(isinstance(row, dict) for row in data)def read(self, source: str) -> List[Dict]:try:with open(source, 'r', encoding='utf-8') as f:return list(csv.DictReader(f))except Exception as e:raise ValueError(f"CSV读取错误: {e}")def write(self, data: List[Dict], destination: str) -> bool:if not self.validate(data):raise ValueError("无效的CSV数据格式")try:with open(destination, 'w', newline='', encoding='utf-8') as f:if not data:return Truewriter = csv.DictWriter(f, fieldnames=data[0].keys())writer.writeheader()writer.writerows(data)return Trueexcept Exception as e:print(f"写入错误: {e}")return Falseclass DataProcessorFactory:"""数据处理器工厂"""_processors: Dict[str, DataProcessor] = {'.json': JSONProcessor(),'.csv': CSVProcessor()}@classmethoddef get_processor(cls, file_path: str) -> DataProcessor:"""根据文件扩展名获取相应的处理器"""import osext = os.path.splitext(file_path)[1].lower()processor = cls._processors.get(ext)if not processor:raise ValueError(f"不支持的文件类型: {ext}")return processor# 使用示例
def convert_file(source: str, destination: str):"""文件转换功能"""try:# 获取源文件和目标文件的处理器source_processor = DataProcessorFactory.get_processor(source)dest_processor = DataProcessorFactory.get_processor(destination)# 读取源文件data = source_processor.read(source)# 写入目标文件if dest_processor.write(data, destination):print(f"文件转换成功: {source} -> {destination}")else:print("文件转换失败")except Exception as e:print(f"转换错误: {e}")# 测试文件转换
if __name__ == "__main__":# JSON到CSV的转换convert_file("data.json", "output.csv")# CSV到JSON的转换convert_file("data.csv", "output.json")

5. 实战案例:图形计算器 📐

让我们创建一个图形计算器,它能够处理不同类型的图形,计算它们的面积和周长:

from abc import ABC, abstractmethod
from typing import List
import mathclass Shape(ABC):"""抽象基类:形状"""@abstractmethoddef area(self) -> float:"""计算面积"""pass@abstractmethoddef perimeter(self) -> float:"""计算周长"""pass@abstractmethoddef description(self) -> str:"""返回形状描述"""passclass Rectangle(Shape):"""矩形类"""def __init__(self, width: float, height: float):if width <= 0 or height <= 0:raise ValueError("矩形的宽和高必须为正数")self._width = widthself._height = heightdef area(self) -> float:return self._width * self._heightdef perimeter(self) -> float:return 2 * (self._width + self._height)def description(self) -> str:return f"矩形(宽={self._width}, 高={self._height})"class Circle(Shape):"""圆形类"""def __init__(self, radius: float):if radius <= 0:raise ValueError("圆的半径必须为正数")self._radius = radiusdef area(self) -> float:return math.pi * self._radius ** 2def perimeter(self) -> float:return 2 * math.pi * self._radiusdef description(self) -> str:return f"圆形(半径={self._radius})"class Triangle(Shape):"""三角形类"""def __init__(self, a: float, b: float, c: float):if not self._is_valid_triangle(a, b, c):raise ValueError("无效的三角形边长")self._sides = (a, b, c)@staticmethoddef _is_valid_triangle(a: float, b: float, c: float) -> bool:"""检查三条边是否能构成三角形"""return (a > 0 and b > 0 and c > 0 anda + b > c and b + c > a and a + c > b)def area(self) -> float:"""使用海伦公式计算面积"""a, b, c = self._sidess = (a + b + c) / 2  # 半周长return math.sqrt(s * (s - a) * (s - b) * (s - c))def perimeter(self) -> float:return sum(self._sides)def description(self) -> str:return f"三角形(边长={', '.join(map(str, self._sides))})"class GeometryCalculator:"""几何计算器类"""def __init__(self):self._shapes: List[Shape] = []def add_shape(self, shape: Shape):"""添加形状"""self._shapes.append(shape)print(f"已添加: {shape.description()}")def calculate_total_area(self) -> float:"""计算所有形状的总面积"""return sum(shape.area() for shape in self._shapes)def calculate_total_perimeter(self) -> float:"""计算所有形状的总周长"""return sum(shape.perimeter() for shape in self._shapes)def show_all_shapes(self):"""显示所有形状的信息"""print("\n形状列表:")for i, shape in enumerate(self._shapes, 1):print(f"{i}. {shape.description()}")print(f"   面积: {shape.area():.2f}")print(f"   周长: {shape.perimeter():.2f}")def main():# 创建计算器实例calculator = GeometryCalculator()# 添加一些形状try:calculator.add_shape(Rectangle(5, 3))calculator.add_shape(Circle(4))calculator.add_shape(Triangle(3, 4, 5))# 显示所有形状信息calculator.show_all_shapes()# 显示总计print(f"\n总面积: {calculator.calculate_total_area():.2f}")print(f"总周长: {calculator.calculate_total_perimeter():.2f}")except ValueError as e:print(f"错误: {e}")if __name__ == "__main__":main()

实战案例特点:

  1. 抽象基类:使用Shape作为抽象基类,定义了必须实现的方法
  2. 继承与多态:各种具体图形类继承自Shape
  3. 封装:使用私有属性保护数据
  4. 类型提示:使用typing模块增加代码可读性
  5. 错误处理:包含适当的验证和异常处理
  6. 静态方法:用于辅助功能(如三角形的有效性检查)

扩展建议:

  1. 添加更多图形类型(如多边形、椭圆等)
  2. 实现图形的缩放和旋转
  3. 添加图形的绘制功能
  4. 实现文件保存和加载功能
  5. 添加图形组合功能
  6. 实现简单的GUI界面
  7. 添加单位转换功能

这个实战案例展示了面向对象编程的进阶概念,包括继承、多态、封装和抽象类的实际应用。它提供了一个可扩展的框架,可以根据需要添加更多功能。


如果你觉得这篇文章有帮助,欢迎点赞转发,也期待在评论区看到你的想法和建议!👇

咱们下一期见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475232.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch奇怪错误

ValueError: At least one stride in the given numpy array is negative, and tensors with negative strides are not currently supported. (You can probably work around this by making a copy of your array with array.copy().) 今天在这里遇到了一个奇怪的bug impor…

EDA实验设计-led灯管动态显示;VHDL;Quartus编程

EDA实验设计-led灯管动态显示&#xff1b;VHDL&#xff1b;Quartus编程 引脚配置实现代码RTL引脚展示现象记录效果展示 引脚配置 #------------------GLOBAL--------------------# set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_…

151页PDF | XX集团数字化转型SAP项目规划方案(限免下载)

一、前言 这份报告是XX集团数字化转型SAP项目规划方案&#xff0c;该报告涵盖了集团战略解读、管理痛点分析、信息化建设目标、整体架构方案、实施策略、SAP系统价值和预期收益&#xff0c;旨在通过数字化推动集团运营模式变革&#xff0c;实现降本增效和价值创新。 《XX集团…

共建智能软件开发联合实验室,怿星科技助力东风柳汽加速智能化技术创新

11月14日&#xff0c;以“奋进70载&#xff0c;智创新纪元”为主题的2024东风柳汽第二届科技周在柳州盛大开幕&#xff0c;吸引了来自全国的汽车行业嘉宾、技术专家齐聚一堂&#xff0c;共襄盛举&#xff0c;一同探寻如何凭借 “新技术、新实力” 这一关键契机&#xff0c;为新…

在 cmd 输入 python.exe 后不报错也无反应的问题

在 cmd 输入 python.exe 后不报错&#xff1a;‘python.exe ’不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件&#xff0c;也无反应。只是显示这样一个弹窗&#xff1a; 查了下环境变量path&#xff0c;看看有什么地方有python.exe&#xff0c;发现原来在C:\Us…

算法日记 30 day 动态规划(背包问题)

今天是动态规划的另一个大类&#xff0c;背包问题。 背包问题的分类 这张图中涵盖了我们能遇到的绝大部分背包问题。 首先是01背包问题 01背包问题 01背包问题&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value…

如何修复WordPress卡在维护模式

当你管理WordPress网站时&#xff0c;没有什么比看到它卡在维护模式更令人沮丧的了。特别是在你进行重要更新或期望大量流量的时候&#xff0c;这种情况会更加令人不安。 维护模式可能由许多因素引起&#xff0c;从简单的文件损坏到更复杂的插件冲突或存在的.maintenance文件。…

Oracle OCP认证考试考点详解082系列22

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 105. 第105题&#xff1a; 题目 解析及答案&#xff1a; 题目翻译&#xff1a; 关于Oracle数据库中的事务请选择两个正确的陈述&#xf…

目录背景缺少vscode右键打开选项

目录背景缺少vscode右键打开选项 1.打开右键管理 下载地址&#xff1a;https://wwyz.lanzoul.com/iZy9G2fl28uj 2.开始搜索框搜索vscode&#xff0c; 找到其源目录 3.目录背景里面&#xff0c; 加入vscode.exe 3.然后在目录背景下&#xff0c; 右键&#xff0c; code就可以打…

第三届航空航天与控制工程国际学术会议 (ICoACE 2024)

重要信息 会议官网&#xff1a;www.icoace.com 线下召开&#xff1a;2024年11月29日-12月1日 会议地点&#xff1a;陕西西安理工大学金花校区 &#xff08;西安市金花南路5号&#xff09; 大会简介 2024年第三届航空航天与控制工程国际学术会议&#xff08;ICoACE 2024&a…

【团购核销】抖音生活服务商家应用快速接入①——基础工作

文章目录 一、前言二、抖音开放平台&#xff08;服务商平台&#xff09;三、认证服务能力四、第三方生活服务商家应用五、APPID和AppSecret六、申请接口权限七、开发配置八、参考 一、前言 目的&#xff1a;将抖音团购核销的功能集成到我们自己开发的App和小程序中 名词解释技术…

十六.SpringCloudAlibaba极简入门-整合Grpc代替OpenFeign

前言 他来了他来了&#xff0c;停了快2个月了终于又开始更新文章啦&#xff0c;这次带来的绝对是干货&#xff01;&#xff01;&#xff01;。由于公司项目进行重构的时候考虑到&#xff0c;OpenFeign做为服务通信组件在高并发情况下有一定的性能瓶颈&#xff0c;所以将其替换…

MySQL库和表的操作

目录 一. 查看数据库 二. 创建数据库 三. 字符集和校验规则 四. 修改和删除数据库 4.1 数据库修改 4.2 数据库删除 五. 备份与恢复 5.1 备份 5.2 还原 5.3 注意事项 5.4 查看连接情况 六. 创建表 七. 查看表结构 八. 修改表 九. …

在Linux下配置gitee与Github的远程仓库

目录 前言 云服务器下载git 检测是否下载成功git Linux下配置gitee远程仓库 代码提交演示 git三板斧 Linux下配置Github远程仓库 最后的提醒 前言 那么本篇文章将是在&#xff0c;你已经创建了本地仓库的基础上&#xff0c;在Linux下配置gitee的远程仓库的步骤&#xff…

mini-lsm通关笔记Week2Day5

项目地址&#xff1a;https://github.com/skyzh/mini-lsm 个人实现地址&#xff1a;https://gitee.com/cnyuyang/mini-lsm Summary 在本章中&#xff0c;您将&#xff1a; 实现manifest文件的编解码。系统重启时从manifest文件中恢复。 要将测试用例复制到启动器代码中并运行…

ESP8266 STA模式TCP服务器 电脑手机网络调试助手

STA模式TCP服务器和手机电脑网络调试助手多连接

JMeter监听器与压测监控之Grafana

Grafana 是一个开源的度量分析和可视化套件&#xff0c;通常用于监控和观察系统和应用的性能。本文将指导你如何在 Kali Linux 上使用 Docker 来部署 Grafana 性能监控平台。 前提条件 Kali Linux&#xff1a;确保你已经安装了 Kali Linux。Docker&#xff1a;确保你的系统已…

基于AIRTEST和Jmeter、Postman的自动化测试框架

基于目前项目和团队技术升级&#xff0c;采用了UI自动化和接口自动化联动数据&#xff0c;进行相关测试活动&#xff0c;获得更好的测试质量和测试结果。

STM32设计防丢防摔智能行李箱-分享

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着科技的不断发展&#xff0c;嵌入式系统、物联网技术、智能设备…

全面解析:HTML页面的加载全过程(一)--输入URL地址,与服务器建立连接

用户输入URL地址&#xff0c;与服务器建立连接 用户在浏览器地址栏输入一个URL 浏览器开始执行以下三步操作操作&#xff1a;url解析、DNS查询、TCP连接 第一步&#xff1a;URL解析 什么是URL&#xff1f; URL(Uniform Resource Locator&#xff0c;统一资源定位符)是互联网…