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

devtools/2024/12/4 3:09:58/

Python面向对象进阶 🚀

1. 继承与多态 🔄

1.1 继承基础

python">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 多态

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

python">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 多重继承

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

python">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的封装机制:

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)

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

python">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)

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

python">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. 抽象类与接口 🎯

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

python">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. 实战案例:图形计算器 📐

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

python">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.ppmy.cn/devtools/136018.html

相关文章

失落的Apache JDBM(Java Database Management)

简介 Apache JDBM&#xff08;Java Database Management&#xff09;是一个轻量级的、基于 Java 的嵌入式数据库管理系统。它主要用于在 Java 应用程序中存储和管理数据。这个项目已经过时了&#xff0c;只是发表一下以示纪念&#xff0c;现在已经大多数被SQLite和Derby代替。…

git commit -m ‘last‘什么意思和git add.什么意思

git add. git commit -m ‘last’ git add . 是一条 Git 命令&#xff0c;用于将当前工作目录中的所有更改添加到暂存区&#xff08;staging area&#xff09;。暂存区是 Git 中的一个临时区域&#xff0c;用于存放即将提交的更改。让我们详细解释一下这条命令的各个部分和它的…

用匠心精神解决LeetCode第726题原子的数量

726.原子的数量 难度&#xff1a;困难 问题描述&#xff1a; 给你一个字符串化学式formula&#xff0c;返回每种原子的数量。 原子总是以一个大写字母开始&#xff0c;接着跟随0个或任意个小写字母&#xff0c;表示原子的名字。 如果数量大于1&#xff0c;原子后会跟着数字…

在应用启动时,使用 UniApp 提供的 API 检查和请求权限。

在使用 UniApp 开发 App 时&#xff0c;如果你需要在应用启动时提示用户获取本地媒体权限&#xff0c;可以按照以下步骤操作&#xff1a; 1. 明确需要的权限 要访问本地媒体&#xff08;如相机、麦克风或文件存储&#xff09;&#xff0c;需要申请以下权限&#xff1a; Andr…

实验室管理技术革新:Spring Boot系统

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

后量子聚合签名;后量子聚合签名和MuSig2区别;量子攻击

目录 后量子聚合签名 后量子聚合签名简介 使用哈希函数实现后量子聚合签名 简单举例说明 优势 后量子聚合签名和MuSig2区别 一、定义与背景 二、技术特点 三、应用场景 量子攻击 1. 量子攻击的基本原理 2. 量子攻击的简单举例 3. 量子攻击的影响与防范 后量子聚合签…

Jenkins更换主题颜色+登录页面LOGO图片

默认主题和logo图片展示 默认主题黑色和白色。 默认LOGO图片 安装插件 Login ThemeMaterial Theme 系统管理–>插件管理–>Available plugins 搜不到Login Theme是因为我提前装好了 没有外网的可以参考这篇离线安装插件 验证插件并修改主题颜色 系统管理–>A…

使用chatGLM-4创建第一个AutoGen实例

本教程将指导你如何使用AutoGen库创建一个智能对话助手&#xff0c;并通过一个简单的例子展示其功能。 环境配置 首先&#xff0c;创建一个独立的Python环境并安装必要的库。 创建Conda环境 打开终端或命令提示符&#xff0c;运行以下命令创建一个新的Conda环境&#xff1a…