python基础-面向对象编程(OOP)
面向对象编程(OOP)
面向对象编程是一种编程范式,它使用"对象"来设计应用程序和计算机程序。Python是一种面向对象的编程语言,支持封装、继承和多态等核心概念。
面向对象编程核心概念图:
┌─────────────────────────────────────────────┐
│ 面向对象编程 │
├─────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 封装 │ │ 继承 │ │ 多态 │ │
│ │Encap- │ │Inherit- │ │Polymor- │ │
│ │sulation │ │ance │ │phism │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 隐藏实现 代码重用 统一接口 │
│ 数据保护 扩展功能 灵活调用 │
│ │
└─────────────────────────────────────────────┘
类与对象
类是对象的蓝图或模板,对象是类的实例。
1. 类的定义与实例化
# 定义一个简单的类
class Person:"""人员类"""# 类变量(所有实例共享)species = "Homo sapiens"population = 0def __init__(self, name, age):"""构造方法(初始化方法)"""# 实例变量(每个实例独有)self.name = nameself.age = agePerson.population += 1 # 增加人口计数def introduce(self):"""自我介绍方法"""return f"你好,我是{self.name},今年{self.age}岁"def have_birthday(self):"""过生日,年龄增加1"""self.age += 1return f"{self.name}过生日了!现在{self.age}岁"def __str__(self):"""字符串表示方法"""return f"Person(name='{self.name}', age={self.age})"def __repr__(self):"""开发者友好的字符串表示"""return f"Person('{self.name}', {self.age})"# 创建对象(实例化)
person1 = Person("张三", 25)
person2 = Person("李四", 30)
person3 = Person("王五", 28)# 访问实例变量和方法
print(person1.introduce())
print(person2.introduce())# 调用方法
print(person1.have_birthday())
print(person1.introduce())# 访问类变量
print(f"物种: {Person.species}")
print(f"总人口: {Person.population}")# 字符串表示
print(f"str表示: {str(person1)}")
print(f"repr表示: {repr(person1)}")
print(f"直接打印: {person1}")
2. 类变量与实例变量
class BankAccount:"""银行账户类"""# 类变量bank_name = "Python银行"interest_rate = 0.03 # 3%年利率total_accounts = 0def __init__(self, account_holder, initial_balance=0):"""初始化账户"""# 实例变量self.account_holder = account_holderself.balance = initial_balanceself.account_number = f"ACC{BankAccount.total_accounts + 1:06d}"self.transaction_history = []# 更新类变量BankAccount.total_accounts += 1# 记录开户交易self._add_transaction("开户", initial_balance)def _add_transaction(self, transaction_type, amount):"""私有方法:添加交易记录"""from datetime import datetimetransaction = {"type": transaction_type,"amount": amount,"balance": self.balance,"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}self.transaction_history.append(transaction)def deposit(self, amount):"""存款"""if amount <= 0:raise ValueError("存款金额必须大于0")self.balance += amountself._add_transaction("存款", amount)return f"存款成功!当前余额: ¥{self.balance:.2f}"def withdraw(self, amount):"""取款"""if amount <= 0:raise ValueError("取款金额必须大于0")if amount > self.balance:raise ValueError("余额不足")self.balance -= amountself._add_transaction("取款", -amount)return f"取款成功!当前余额: ¥{self.balance:.2f}"def get_balance(self):"""查询余额"""return self.balancedef calculate_interest(self):"""计算利息"""interest = self.balance * self.interest_ratereturn interestdef apply_interest(self):"""应用利息"""interest = self.calculate_interest()self.balance += interestself._add_transaction("利息", interest)return f"利息已到账!利息金额: ¥{interest:.2f},当前余额: ¥{self.balance:.2f}"def get_account_info(self):"""获取账户信息"""return {"account_number": self.account_number,"account_holder": self.account_holder,"balance": self.balance,"bank_name": self.bank_name,"interest_rate": self.interest_rate}def print_statement(self):"""打印账户对账单"""print(f"\n=== {self.bank_name} 账户对账单 ===")print(f"账户号码: {self.account_number}")print(f"账户持有人: {self.account_holder}")print(f"当前余额: ¥{self.balance:.2f}")print(f"年利率: {self.interest_rate*100:.1f}%")print("\n交易历史:")for transaction in self.transaction_history:print(f"{transaction['timestamp']} | {transaction['type']:6s} | "f"¥{transaction['amount']:8.2f} | 余额: ¥{transaction['balance']:.2f}")@classmethoddef get_bank_info(cls):"""类方法:获取银行信息"""return {"bank_name": cls.bank_name,"total_accounts": cls.total_accounts,"interest_rate": cls.interest_rate}@classmethoddef set_interest_rate(cls, new_rate):"""类方法:设置利率"""if new_rate < 0:raise ValueError("利率不能为负数")cls.interest_rate = new_ratereturn f"利率已更新为 {new_rate*100:.2f}%"@staticmethoddef calculate_compound_interest(principal, rate, time):"""静态方法:计算复利"""return principal * (1 + rate) ** timedef __str__(self):return f"BankAccount({self.account_holder}, ¥{self.balance:.2f})"def __repr__(self):return f"BankAccount('{self.account_holder}', {self.balance})"# 使用银行账户类
print("=== 银行账户系统演示 ===")# 创建账户
account1 = BankAccount("张三", 1000)
account2 = BankAccount("李四", 2000)
account3 = BankAccount("王五")# 基本操作
print(account1.deposit(500))
print(account1.withdraw(200))
print(account2.deposit(1000))# 查询余额
print(f"\n{account1.account_holder}的余额: ¥{account1.get_balance():.2f}")
print(f"{account2.account_holder}的余额: ¥{account2.get_balance():.2f}")# 计算和应用利息
print(f"\n{account1.account_holder}的年利息: ¥{account1.calculate_interest():.2f}")
print(account1.apply_interest())# 使用类方法
print(f"\n银行信息: {BankAccount.get_bank_info()}")
print(BankAccount.set_interest_rate(0.035))# 使用静态方法
compound_result = BankAccount.calculate_compound_interest(1000, 0.035, 5)
print(f"\n1000元,3.5%利率,5年复利结果: ¥{compound_result:.2f}")# 打印对账单
account1.print_statement()
构造方法(init)
构造方法是在创建对象时自动调用的特殊方法,用于初始化对象的状态。
1. 基本构造方法
class Student:"""学生类"""def __init__(self, name, student_id, major, year=1):"""初始化学生对象"""# 验证输入if not name or not isinstance(name, str):raise ValueError("姓名必须是非空字符串")if not student_id or not isinstance(student_id, str):raise ValueError("学号必须是非空字符串")if year < 1 or year > 4:raise ValueError("年级必须在1-4之间")# 初始化实例变量self.name = nameself.student_id = student_idself.major = majorself.year = yearself.courses = [] # 选修课程列表self.grades = {} # 成绩字典self.gpa = 0.0 # 平均绩点def enroll_course(self, course_name, credits=3):"""选课"""course = {"name": course_name,"credits": credits,"grade": None}self.courses.append(course)return f"{self.name} 已选修课程: {course_name} ({credits}学分)"def add_grade(self, course_name, grade):"""添加成绩"""if grade < 0 or grade > 100:raise ValueError("成绩必须在0-100之间")# 查找课程并添加成绩for course in self.courses:if course["name"] == course_name:course["grade"] = gradeself.grades[course_name] = gradeself._calculate_gpa()return f"{course_name} 成绩已录入: {grade}分"raise ValueError(f"未找到课程: {course_name}")def _calculate_gpa(self):"""私有方法:计算GPA"""if not self.grades:self.gpa = 0.0returntotal_points = 0total_credits = 0for course in self.courses:if course["grade"] is not None:# 简化的GPA计算:90-100=4.0, 80-89=3.0, 70-79=2.0, 60-69=1.0, <60=0.0grade = course["grade"]if grade >= 90:points = 4.0elif grade >= 80:points = 3.0elif grade >= 70:points = 2.0elif grade >= 60:points = 1.0else:points = 0.0total_points += points * course["credits"]total_credits += course["credits"]self.gpa = total_points / total_credits if total_credits > 0 else 0.0def get_transcript(self):"""获取成绩单"""transcript = {"student_info": {"name": self.name,"student_id": self.student_id,"major": self.major,"year": self.year},"courses": self.courses.copy(),"gpa": round(self.gpa, 2),"total_credits": sum(course["credits"] for course in self.courses if course["grade"] is not None)}return transcriptdef print_transcript(self):"""打印成绩单"""print(f"\n=== {self.name} 的成绩单 ===")print(f"学号: {self.student_id}")print(f"专业: {self.major}")print(f"年级: {self.year}")print(f"GPA: {self.gpa:.2f}")print("\n课程成绩:")print("-" * 50)print(f"{'课程名称':<20} {'学分':<6} {'成绩':<6} {'等级':<6}")print("-" * 50)for course in self.courses:grade = course["grade"]if grade is not None:if grade >= 90:level = "A"elif grade >= 80:level = "B"elif grade >= 70:level = "C"elif grade >= 60:level = "D"else:level = "F"print(f"{course['name']:<20} {course['credits']:<6} {grade:<6} {level:<6}")else:print(f"{course['name']:<20} {course['credits']:<6} {'--':<6} {'--':<6}")print("-" * 50)total_credits = sum(course["credits"] for course in self.courses if course["grade"] is not None)print(f"总学分: {total_credits}")print(f"平均绩点: {self.gpa:.2f}")def __str__(self):return f"Student({self.name}, {self.student_id}, {self.major}, Year {self.year})"def __repr__(self):return f"Student('{self.name}', '{self.student_id}', '{self.major}', {self.year})"# 使用学生类
print("=== 学生管理系统演示 ===")# 创建学生对象
student1 = Student("张三", "2023001", "计算机科学", 2)
student2 = Student("李四", "2023002", "数学", 1)# 选课
print(student1.enroll_course("数据结构", 4))
print(student1.enroll_course("算法分析", 3))
print(student1.enroll_course("数据库系统", 3))print(student2.enroll_course("高等数学", 5))
print(student2.enroll_course("线性代数", 4))# 录入成绩
print("\n录入成绩:")
print(student1.add_grade("数据结构", 92))
print(student1.add_grade("算法分析", 88))
print(student1.add_grade("数据库系统", 85))print(student2.add_grade("高等数学", 95))
print(student2.add_grade("线性代数", 90))# 打印成绩单
student1.print_transcript()
student2.print_transcript()
2. 多种初始化方式
class Rectangle:"""矩形类,支持多种初始化方式"""def __init__(self, *args, **kwargs):"""灵活的构造方法"""if len(args) == 1 and isinstance(args[0], (int, float)):# 正方形:Rectangle(5)self.width = self.height = args[0]elif len(args) == 2:# 矩形:Rectangle(5, 3)self.width, self.height = argselif 'width' in kwargs and 'height' in kwargs:# 关键字参数:Rectangle(width=5, height=3)self.width = kwargs['width']self.height = kwargs['height']elif 'size' in kwargs:# 正方形:Rectangle(size=5)self.width = self.height = kwargs['size']else:# 默认值:Rectangle()self.width = self.height = 1# 验证参数if self.width <= 0 or self.height <= 0:raise ValueError("宽度和高度必须大于0")# 设置其他属性self.color = kwargs.get('color', 'white')self.border_width = kwargs.get('border_width', 1)def area(self):"""计算面积"""return self.width * self.heightdef perimeter(self):"""计算周长"""return 2 * (self.width + self.height)def is_square(self):"""判断是否为正方形"""return self.width == self.heightdef scale(self, factor):"""缩放矩形"""self.width *= factorself.height *= factorreturn selfdef __str__(self):shape_type = "正方形" if self.is_square() else "矩形"return f"{shape_type}(宽={self.width}, 高={self.height}, 颜色={self.color})"def __repr__(self):return f"Rectangle({self.width}, {self.height})"def __eq__(self, other):"""相等比较"""if not isinstance(other, Rectangle):return Falsereturn self.width == other.width and self.height == other.heightdef __lt__(self, other):"""小于比较(按面积)"""if not isinstance(other, Rectangle):return NotImplementedreturn self.area() < other.area()# 测试多种初始化方式
print("=== 矩形类多种初始化方式 ===")# 不同的创建方式
rect1 = Rectangle(5, 3) # 矩形
rect2 = Rectangle(4) # 正方形
rect3 = Rectangle(width=6, height=2, color='red') # 关键字参数
rect4 = Rectangle(size=3, color='blue', border_width=2) # 正方形
rect5 = Rectangle() # 默认值rectangles = [rect1, rect2, rect3, rect4, rect5]for i, rect in enumerate(rectangles, 1):print(f"\n矩形{i}: {rect}")print(f" 面积: {rect.area()}")print(f" 周长: {rect.perimeter()}")print(f" 是否为正方形: {rect.is_square()}")# 比较操作
print(f"\n矩形比较:")
print(f"rect1 == rect2: {rect1 == rect2}")
print(f"rect1 < rect3: {rect1 < rect3}")# 缩放操作
print(f"\n缩放前 rect1: {rect1}")
rect1.scale(1.5)
print(f"缩放后 rect1: {rect1}")
实例方法与类方法
Python中有三种类型的方法:实例方法、类方法和静态方法。
1. 实例方法、类方法和静态方法
class MathUtils:"""数学工具类,演示不同类型的方法"""# 类变量pi = 3.14159265359calculation_count = 0def __init__(self, precision=2):"""初始化"""self.precision = precision # 实例变量self.history = [] # 计算历史# 实例方法(需要self参数)def round_number(self, number):"""实例方法:根据实例的精度设置四舍五入"""result = round(number, self.precision)self.history.append(f"round({number}) = {result}")MathUtils.calculation_count += 1return resultdef calculate_circle_area(self, radius):"""实例方法:计算圆面积"""area = self.pi * radius ** 2result = self.round_number(area)self.history.append(f"circle_area(r={radius}) = {result}")return resultdef get_history(self):"""实例方法:获取计算历史"""return self.history.copy()def clear_history(self):"""实例方法:清空计算历史"""self.history.clear()return "计算历史已清空"# 类方法(需要cls参数,使用@classmethod装饰器)@classmethoddef get_calculation_count(cls):"""类方法:获取总计算次数"""return cls.calculation_count@classmethoddef reset_calculation_count(cls):"""类方法:重置计算次数"""cls.calculation_count = 0return "计算次数已重置"@classmethoddef set_pi(cls, new_pi):"""类方法:设置π的值"""if new_pi <= 0:raise ValueError("π必须大于0")old_pi = cls.picls.pi = new_pireturn f"π已从{old_pi}更新为{new_pi}"@classmethoddef create_high_precision(cls):"""类方法:创建高精度实例"""return cls(precision=6)@classmethoddef create_low_precision(cls):"""类方法:创建低精度实例"""return cls(precision=0)# 静态方法(不需要self或cls参数,使用@staticmethod装饰器)@staticmethoddef is_even(number):"""静态方法:判断是否为偶数"""return number % 2 == 0@staticmethoddef is_prime(n):"""静态方法:判断是否为质数"""if n < 2:return Falseif n == 2:return Trueif n % 2 == 0:return Falsefor i in range(3, int(n ** 0.5) + 1, 2):if n % i == 0:return Falsereturn True@staticmethoddef factorial(n):"""静态方法:计算阶乘"""if n < 0:raise ValueError("阶乘的参数必须是非负整数")if n == 0 or n == 1:return 1result = 1for i in range(2, n + 1):result *= ireturn result@staticmethoddef gcd(a, b):"""静态方法:计算最大公约数"""while b:a, b = b, a % breturn abs(a)@staticmethoddef convert_temperature(temp, from_unit, to_unit):"""静态方法:温度转换"""# 先转换为摄氏度if from_unit.lower() == 'f':celsius = (temp - 32) * 5/9elif from_unit.lower() == 'k':celsius = temp - 273.15else:celsius = temp# 再转换为目标单位if to_unit.lower() == 'f':return celsius * 9/5 + 32elif to_unit.lower() == 'k':return celsius + 273.15else:return celsiusdef __str__(self):return f"MathUtils(precision={self.precision}, calculations={len(self.history)})"def __repr__(self):return f"MathUtils({self.precision})"# 使用不同类型的方法
print("=== 方法类型演示 ===")# 创建实例
math1 = MathUtils(2) # 精度为2
math2 = MathUtils(4) # 精度为4# 使用实例方法
print("\n=== 实例方法 ===")
print(f"math1圆面积(r=5): {math1.calculate_circle_area(5)}")
print(f"math2圆面积(r=5): {math2.calculate_circle_area(5)}")
print(f"math1四舍五入(3.14159): {math1.round_number(3.14159)}")
print(f"math2四舍五入(3.14159): {math2.round_number(3.14159)}")print(f"\nmath1计算历史: {math1.get_history()}")
print(f"math2计算历史: {math2.get_history()}")# 使用类方法
print("\n=== 类方法 ===")
print(f"总计算次数: {MathUtils.get_calculation_count()}")
print(f"当前π值: {MathUtils.pi}")# 通过类调用类方法
print(MathUtils.set_pi(3.141592653589793))
print(f"更新后π值: {MathUtils.pi}")# 通过实例也可以调用类方法(但不推荐)
print(f"通过实例调用类方法: {math1.get_calculation_count()}")# 使用类方法创建特殊实例
high_precision = MathUtils.create_high_precision()
low_precision = MathUtils.create_low_precision()print(f"\n高精度实例: {high_precision}")
print(f"低精度实例: {low_precision}")print(f"高精度圆面积(r=3): {high_precision.calculate_circle_area(3)}")
print(f"低精度圆面积(r=3): {low_precision.calculate_circle_area(3)}")# 使用静态方法
print("\n=== 静态方法 ===")
print(f"17是偶数: {MathUtils.is_even(17)}")
print(f"18是偶数: {MathUtils.is_even(18)}")
print(f"17是质数: {MathUtils.is_prime(17)}")
print(f"18是质数: {MathUtils.is_prime(18)}")
print(f"5的阶乘: {MathUtils.factorial(5)}")
print(f"48和18的最大公约数: {MathUtils.gcd(48, 18)}")# 温度转换
print(f"\n温度转换:")
print(f"100°C = {MathUtils.convert_temperature(100, 'C', 'F'):.1f}°F")
print(f"32°F = {MathUtils.convert_temperature(32, 'F', 'C'):.1f}°C")
print(f"273.15K = {MathUtils.convert_temperature(273.15, 'K', 'C'):.1f}°C")# 静态方法可以通过类或实例调用
print(f"\n通过类调用静态方法: {MathUtils.is_prime(29)}")
print(f"通过实例调用静态方法: {math1.is_prime(29)}")# 重置计算次数
print(f"\n{MathUtils.reset_calculation_count()}")
print(f"重置后计算次数: {MathUtils.get_calculation_count()}")
2. 方法类型的选择指南
class MethodSelectionGuide:"""方法选择指南类"""class_variable = "我是类变量"def __init__(self, instance_data):self.instance_data = instance_data# 实例方法:需要访问实例数据时使用def instance_method(self):"""使用实例方法的情况:1. 需要访问或修改实例变量2. 需要调用其他实例方法3. 行为依赖于实例的状态"""return f"实例方法访问实例数据: {self.instance_data}"# 类方法:需要访问类数据或创建实例时使用@classmethoddef class_method(cls):"""使用类方法的情况:1. 需要访问或修改类变量2. 创建实例的替代构造器3. 操作与类相关但不依赖实例的数据"""return f"类方法访问类变量: {cls.class_variable}"@classmethoddef alternative_constructor(cls, data_string):"""替代构造器示例"""# 解析字符串并创建实例processed_data = data_string.upper()return cls(processed_data)# 静态方法:与类相关但不需要访问类或实例数据时使用@staticmethoddef static_method(param1, param2):"""使用静态方法的情况:1. 功能与类相关但不需要访问类或实例数据2. 可以独立运行的工具函数3. 为了代码组织而放在类中的函数"""return f"静态方法处理参数: {param1} + {param2} = {param1 + param2}"def demonstrate_usage(self):"""演示不同方法的使用"""print("=== 方法使用演示 ===")# 实例方法print(f"1. {self.instance_method()}")# 类方法(通过实例调用)print(f"2. {self.class_method()}")# 静态方法(通过实例调用)print(f"3. {self.static_method(10, 20)}")# 演示方法选择
print("=== 方法选择指南 ===")# 创建实例
guide = MethodSelectionGuide("实例数据")
guide.demonstrate_usage()print("\n=== 不同调用方式 ===")# 通过类调用类方法和静态方法
print(f"通过类调用类方法: {MethodSelectionGuide.class_method()}")
print(f"通过类调用静态方法: {MethodSelectionGuide.static_method(5, 15)}")# 使用替代构造器
alt_instance = MethodSelectionGuide.alternative_constructor("hello world")
print(f"\n替代构造器创建的实例: {alt_instance.instance_data}")# 总结
print("\n=== 方法选择总结 ===")
print("""
选择指南:
1. 实例方法 (self):- 需要访问实例变量- 行为依赖于实例状态- 大多数情况下的默认选择2. 类方法 (@classmethod, cls):- 需要访问类变量- 替代构造器- 与类相关但不依赖实例的操作3. 静态方法 (@staticmethod):- 与类相关的工具函数- 不需要访问类或实例数据- 可以独立运行的函数
""")
继承与多态
继承允许一个类获得另一个类的属性和方法,多态允许不同类的对象对同一消息做出响应。
1. 基本继承
# 基类(父类)
class Animal:"""动物基类"""def __init__(self, name, species, age):self.name = nameself.species = speciesself.age = ageself.is_alive = Truedef eat(self, food):"""吃东西"""return f"{self.name}正在吃{food}"def sleep(self):"""睡觉"""return f"{self.name}正在睡觉"def make_sound(self):"""发出声音(基类中的通用实现)"""return 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"Animal(name='{self.name}', species='{self.species}', age={self.age})"def __repr__(self):return f"Animal('{self.name}', '{self.species}', {self.age})"# 派生类(子类)
class Dog(Animal):"""狗类,继承自Animal"""def __init__(self, name, breed, age, owner=None):# 调用父类的构造方法super().__init__(name, "狗", age)# 添加子类特有的属性self.breed = breedself.owner = ownerself.tricks = [] # 会的技能def make_sound(self):"""重写父类方法"""return f"{self.name}汪汪叫"def fetch(self, item):"""狗特有的方法:捡东西"""return f"{self.name}去捡{item}了"def learn_trick(self, trick):"""学习新技能"""if trick not in self.tricks:self.tricks.append(trick)return f"{self.name}学会了{trick}"return f"{self.name}已经会{trick}了"def perform_trick(self, trick):"""表演技能"""if trick in self.tricks:return f"{self.name}表演了{trick}"return f"{self.name}不会{trick}"def get_info(self):"""重写父类方法,添加更多信息"""base_info = super().get_info() # 调用父类方法owner_info = f",主人:{self.owner}" if self.owner else ",无主人"tricks_info = f",会{len(self.tricks)}个技能" if self.tricks else ",还没学会技能"return f"{base_info},品种:{self.breed}{owner_info}{tricks_info}"class Cat(Animal):"""猫类,继承自Animal"""def __init__(self, name, breed, age, indoor=True):super().__init__(name, "猫", age)self.breed = breedself.indoor = indoor # 是否为室内猫self.favorite_spots = [] # 喜欢的地点def make_sound(self):"""重写父类方法"""return f"{self.name}喵喵叫"def purr(self):"""猫特有的方法:呼噜"""return f"{self.name}发出呼噜声"def climb(self, location):"""爬到某个地方"""return f"{self.name}爬到了{location}"def add_favorite_spot(self, spot):"""添加喜欢的地点"""if spot not in self.favorite_spots:self.favorite_spots.append(spot)return f"{self.name}现在喜欢{spot}了"return f"{self.name}已经喜欢{spot}了"def get_info(self):"""重写父类方法"""base_info = super().get_info()location_type = "室内猫" if self.indoor else "室外猫"spots_info = f",有{len(self.favorite_spots)}个喜欢的地点" if self.favorite_spots else ",还没有特别喜欢的地点"return f"{base_info},品种:{self.breed},{location_type}{spots_info}"class Bird(Animal):"""鸟类,继承自Animal"""def __init__(self, name, species, age, can_fly=True):super().__init__(name, species, age)self.can_fly = can_flyself.flight_distance = 0 # 飞行距离def make_sound(self):"""重写父类方法"""return f"{self.name}啾啾叫"def fly(self, distance):"""鸟特有的方法:飞行"""if not self.can_fly:return f"{self.name}不会飞"self.flight_distance += distancereturn f"{self.name}飞了{distance}米,总飞行距离:{self.flight_distance}米"def sing(self):"""唱歌"""return f"{self.name}在唱歌"def get_info(self):"""重写父类方法"""base_info = super().get_info()fly_info = "会飞" if self.can_fly else "不会飞"distance_info = f",总飞行距离:{self.flight_distance}米" if self.flight_distance > 0 else ""return f"{base_info},{fly_info}{distance_info}"# 使用继承
print("=== 继承演示 ===")# 创建不同类型的动物
dog = Dog("旺财", "金毛", 3, "张三")
cat = Cat("咪咪", "波斯猫", 2, True)
bird = Bird("小黄", "金丝雀", 1, True)animals = [dog, cat, bird]# 展示基本信息
print("动物信息:")
for animal in animals:print(f" {animal.get_info()}")print("\n基本行为:")
for animal in animals:print(f" {animal.eat('食物')}")print(f" {animal.sleep()}")print(f" {animal.make_sound()}")print()# 展示特有行为
print("特有行为:")
print(dog.fetch("球"))
print(dog.learn_trick("坐下"))
print(dog.learn_trick("握手"))
print(dog.perform_trick("坐下"))print(cat.purr())
print(cat.climb("书架"))
print(cat.add_favorite_spot("阳台"))
print(cat.add_favorite_spot("沙发"))print(bird.fly(100))
print(bird.fly(50))
print(bird.sing())# 更新后的信息
print("\n更新后的动物信息:")
for animal in animals:print(f" {animal.get_info()}")
2. 多重继承
# 多重继承示例
class Flyable:"""可飞行的混入类"""def __init__(self):self.altitude = 0self.max_altitude = 1000def take_off(self):"""起飞"""if self.altitude == 0:self.altitude = 10return f"{getattr(self, 'name', '飞行器')}起飞了,当前高度:{self.altitude}米"return f"{getattr(self, 'name', '飞行器')}已经在飞行中"def land(self):"""降落"""if self.altitude > 0:self.altitude = 0return f"{getattr(self, 'name', '飞行器')}降落了"return f"{getattr(self, 'name', '飞行器')}已经在地面上"def change_altitude(self, delta):"""改变高度"""new_altitude = self.altitude + deltaif new_altitude < 0:new_altitude = 0elif new_altitude > self.max_altitude:new_altitude = self.max_altitudeold_altitude = self.altitudeself.altitude = new_altitudeif delta > 0:return f"{getattr(self, 'name', '飞行器')}上升了{new_altitude - old_altitude}米,当前高度:{self.altitude}米"elif delta < 0:return f"{getattr(self, 'name', '飞行器')}下降了{old_altitude - new_altitude}米,当前高度:{self.altitude}米"else:return f"{getattr(self, 'name', '飞行器')}保持高度:{self.altitude}米"class Swimmable:"""可游泳的混入类"""def __init__(self):self.depth = 0self.max_depth = 100def dive(self, target_depth):"""潜水"""if target_depth > self.max_depth:target_depth = self.max_depthold_depth = self.depthself.depth = target_depthif target_depth > old_depth:return f"{getattr(self, 'name', '游泳者')}潜水到{self.depth}米深"elif target_depth < old_depth:return f"{getattr(self, 'name', '游泳者')}上浮到{self.depth}米深"else:return f"{getattr(self, 'name', '游泳者')}保持在{self.depth}米深"def surface(self):"""浮出水面"""if self.depth > 0:self.depth = 0return f"{getattr(self, 'name', '游泳者')}浮出了水面"return f"{getattr(self, 'name', '游泳者')}已经在水面上"def swim(self, distance):"""游泳"""return f"{getattr(self, 'name', '游泳者')}游了{distance}米"# 多重继承的类
class Duck(Animal, Flyable, Swimmable):"""鸭子类,继承自Animal并混入飞行和游泳能力"""def __init__(self, name, age):# 调用所有父类的构造方法Animal.__init__(self, name, "鸭子", age)Flyable.__init__(self)Swimmable.__init__(self)# 设置鸭子特有的属性self.max_altitude = 500 # 鸭子飞行高度较低self.max_depth = 10 # 鸭子潜水深度较浅def make_sound(self):"""重写父类方法"""return f"{self.name}嘎嘎叫"def paddle(self):"""鸭子特有的方法:划水"""return f"{self.name}在水面上划水"def get_info(self):"""重写父类方法"""base_info = super().get_info()position_info = []if self.altitude > 0:position_info.append(f"飞行高度{self.altitude}米")if self.depth > 0:position_info.append(f"潜水深度{self.depth}米")if position_info:return f"{base_info},当前位置:{', '.join(position_info)}"else:return f"{base_info},在地面/水面上"class Penguin(Animal, Swimmable):"""企鹅类,继承自Animal并混入游泳能力(不能飞行)"""def __init__(self, name, age):Animal.__init__(self, name, "企鹅", age)Swimmable.__init__(self)self.max_depth = 200 # 企鹅潜水能力强def make_sound(self):"""重写父类方法"""return f"{self.name}嘎嘎叫(企鹅版)"def slide(self):"""企鹅特有的方法:滑行"""return f"{self.name}在冰面上滑行"def huddle(self):"""抱团取暖"""return f"{self.name}和其他企鹅抱团取暖"def get_info(self):"""重写父类方法"""base_info = super().get_info()if self.depth > 0:return f"{base_info},正在{self.depth}米深的水中"else:return f"{base_info},在陆地上"# 使用多重继承
print("\n=== 多重继承演示 ===")# 创建具有多种能力的动物
duck = Duck("唐老鸭", 2)
penguin = Penguin("企鹅先生", 3)print("=== 鸭子的能力 ===")
print(duck.get_info())
print(duck.make_sound())
print(duck.eat("小鱼"))# 飞行能力
print("\n飞行测试:")
print(duck.take_off())
print(duck.change_altitude(100))
print(duck.change_altitude(50))
print(duck.land())# 游泳能力
print("\n游泳测试:")
print(duck.swim(20))
print(duck.dive(5))
print(duck.paddle())
print(duck.surface())# 特有方法
print(f"\n{duck.get_info()}")print("\n=== 企鹅的能力 ===")
print(penguin.get_info())
print(penguin.make_sound())
print(penguin.slide())
print(penguin.huddle())# 游泳能力
print("\n游泳测试:")
print(penguin.swim(30))
print(penguin.dive(50))
print(penguin.dive(100))
print(penguin.surface())print(f"\n{penguin.get_info()}")# 检查方法解析顺序(MRO)
print("\n=== 方法解析顺序 ===")
print(f"Duck的MRO: {[cls.__name__ for cls in Duck.__mro__]}")
print(f"Penguin的MRO: {[cls.__name__ for cls in Penguin.__mro__]}")
3. 多态演示
# 多态演示
def animal_concert(animals):"""动物音乐会 - 多态的经典示例"""print("\n🎵 动物音乐会开始了! 🎵")print("=" * 40)for i, animal in enumerate(animals, 1):print(f"{i}. {animal.name}的表演:")print(f" {animal.make_sound()}")# 根据动物类型展示特殊才艺if hasattr(animal, 'sing'):print(f" {animal.sing()}")elif hasattr(animal, 'purr'):print(f" {animal.purr()}")elif hasattr(animal, 'perform_trick') and animal.tricks:trick = animal.tricks[0] if animal.tricks else "坐下"print(f" {animal.perform_trick(trick)}")print()print("🎵 音乐会结束,感谢大家! 🎵")def animal_feeding_time(animals, food):"""喂食时间 - 另一个多态示例"""print(f"\n🍽️ 喂食时间:给动物们喂{food} 🍽️")print("=" * 40)for animal in animals:print(f" {animal.eat(food)}")print()def animal_exercise(animals):"""运动时间 - 展示不同动物的运动方式"""print("\n🏃 运动时间到了! 🏃")print("=" * 40)for animal in animals:print(f"{animal.name}的运动:")# 根据动物的能力进行不同的运动if isinstance(animal, Duck):print(f" {animal.take_off()}")print(f" {animal.change_altitude(50)}")print(f" {animal.swim(100)}")print(f" {animal.land()}")elif isinstance(animal, Penguin):print(f" {animal.slide()}")print(f" {animal.swim(200)}")print(f" {animal.dive(80)}")print(f" {animal.surface()}")elif isinstance(animal, Dog):print(f" {animal.fetch('飞盘')}")if animal.tricks:print(f" {animal.perform_trick(animal.tricks[0])}")elif isinstance(animal, Cat):print(f" {animal.climb('猫爬架')}")print(f" {animal.purr()}")elif isinstance(animal, Bird):print(f" {animal.fly(150)}")print(f" {animal.sing()}")else:print(f" {animal.sleep()}")print()# 创建动物园
print("=== 多态演示:动物园管理系统 ===")# 创建各种动物
zoo_animals = [Dog("旺财", "拉布拉多", 4, "管理员"),Cat("咪咪", "英短", 2),Bird("小蓝", "蓝鹦鹉", 1),Duck("小黄鸭", 1),Penguin("波波", 5)
]# 给狗狗教一些技能
zoo_animals[0].learn_trick("握手")
zoo_animals[0].learn_trick("装死")# 给猫咪添加喜欢的地点
zoo_animals[1].add_favorite_spot("阳台")
zoo_animals[1].add_favorite_spot("纸箱")# 展示多态:所有动物都有相同的接口,但行为不同
print("动物园里的所有动物:")
for animal in zoo_animals:print(f" {animal.get_info()}")# 多态演示
animal_concert(zoo_animals)
animal_feeding_time(zoo_animals, "美味食物")
animal_exercise(zoo_animals)# 统一处理:多态的威力
print("=== 统一处理演示 ===")
print("让所有动物发出声音:")
for animal in zoo_animals:print(f" {animal.make_sound()}")print("\n让所有动物睡觉:")
for animal in zoo_animals:print(f" {animal.sleep()}")
方法重写与重载
Python支持方法重写,但不直接支持方法重载(可以通过默认参数等方式实现类似功能)。
1. 方法重写
class Shape:"""形状基类"""def __init__(self, name):self.name = namedef area(self):"""计算面积 - 基类中的默认实现"""raise NotImplementedError("子类必须实现area方法")def perimeter(self):"""计算周长 - 基类中的默认实现"""raise NotImplementedError("子类必须实现perimeter方法")def describe(self):"""描述形状"""return f"这是一个{self.name}"def get_info(self):"""获取形状信息"""try:area = self.area()perimeter = self.perimeter()return f"{self.describe()},面积:{area:.2f},周长:{perimeter:.2f}"except NotImplementedError:return f"{self.describe()},面积和周长未定义"def __str__(self):return f"Shape({self.name})"class Circle(Shape):"""圆形类"""def __init__(self, radius):super().__init__("圆形")self.radius = radiusdef area(self):"""重写area方法"""import mathreturn math.pi * self.radius ** 2def perimeter(self):"""重写perimeter方法"""import mathreturn 2 * math.pi * self.radiusdef describe(self):"""重写describe方法,添加更多信息"""base_desc = super().describe()return f"{base_desc},半径为{self.radius}"def diameter(self):"""圆形特有的方法"""return 2 * self.radiusdef __str__(self):return f"Circle(radius={self.radius})"class Rectangle(Shape):"""矩形类"""def __init__(self, width, height):super().__init__("矩形")self.width = widthself.height = heightdef area(self):"""重写area方法"""return self.width * self.heightdef perimeter(self):"""重写perimeter方法"""return 2 * (self.width + self.height)def describe(self):"""重写describe方法"""base_desc = super().describe()shape_type = "正方形" if self.width == self.height else "矩形"return f"{base_desc}({shape_type}),宽{self.width},高{self.height}"def is_square(self):"""判断是否为正方形"""return self.width == self.heightdef diagonal(self):"""计算对角线长度"""import mathreturn math.sqrt(self.width ** 2 + self.height ** 2)def __str__(self):return f"Rectangle(width={self.width}, height={self.height})"class Triangle(Shape):"""三角形类"""def __init__(self, a, b, c):super().__init__("三角形")# 验证三角形的有效性if a + b <= c or a + c <= b or b + c <= a:raise ValueError("无效的三角形边长")self.a = aself.b = bself.c = cdef area(self):"""重写area方法 - 使用海伦公式"""import maths = self.perimeter() / 2 # 半周长return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))def perimeter(self):"""重写perimeter方法"""return self.a + self.b + self.cdef describe(self):"""重写describe方法"""base_desc = super().describe()triangle_type = self.get_triangle_type()return f"{base_desc}({triangle_type}),边长:{self.a}, {self.b}, {self.c}"def get_triangle_type(self):"""获取三角形类型"""sides = sorted([self.a, self.b, self.c])if sides[0] == sides[1] == sides[2]:return "等边三角形"elif sides[0] == sides[1] or sides[1] == sides[2]:return "等腰三角形"elif abs(sides[0]**2 + sides[1]**2 - sides[2]**2) < 1e-10:return "直角三角形"else:return "普通三角形"def __str__(self):return f"Triangle(a={self.a}, b={self.b}, c={self.c})"# 方法重写演示
print("=== 方法重写演示 ===")# 创建不同的形状
shapes = [Circle(5),Rectangle(4, 6),Rectangle(5, 5), # 正方形Triangle(3, 4, 5) # 直角三角形
]print("所有形状的信息:")
for shape in shapes:print(f" {shape.get_info()}")print("\n形状描述:")
for shape in shapes:print(f" {shape.describe()}")# 展示特有方法
print("\n特有方法演示:")
for shape in shapes:if isinstance(shape, Circle):print(f" {shape.name}的直径:{shape.diameter():.2f}")elif isinstance(shape, Rectangle):print(f" {shape.name}的对角线:{shape.diagonal():.2f}")print(f" 是否为正方形:{shape.is_square()}")elif isinstance(shape, Triangle):print(f" {shape.name}的类型:{shape.get_triangle_type()}")
2. 模拟方法重载
class Calculator:"""计算器类,演示Python中的方法重载模拟"""def add(self, *args, **kwargs):"""加法方法 - 支持多种参数形式"""if len(args) == 0:return 0elif len(args) == 1:# 单个参数:可能是数字或列表arg = args[0]if isinstance(arg, (list, tuple)):return sum(arg)else:return argelif len(args) == 2:# 两个参数:普通加法return args[0] + args[1]else:# 多个参数:全部相加return sum(args)def multiply(self, *args, **kwargs):"""乘法方法 - 支持多种参数形式"""if len(args) == 0:return 1elif len(args) == 1:arg = args[0]if isinstance(arg, (list, tuple)):result = 1for num in arg:result *= numreturn resultelse:return argelse:result = 1for num in args:result *= numreturn resultdef calculate(self, operation, *args, **kwargs):"""通用计算方法 - 根据操作类型调用不同方法"""operation = operation.lower()if operation in ['add', '+', 'plus']:return self.add(*args, **kwargs)elif operation in ['multiply', '*', 'times']:return self.multiply(*args, **kwargs)elif operation in ['subtract', '-', 'minus']:if len(args) == 2:return args[0] - args[1]elif len(args) > 2:result = args[0]for num in args[1:]:result -= numreturn resultelif operation in ['divide', '/', 'div']:if len(args) == 2:if args[1] == 0:raise ValueError("除数不能为零")return args[0] / args[1]else:raise ValueError(f"不支持的操作:{operation}")def power(self, base, exponent=2):"""幂运算 - 使用默认参数模拟重载"""return base ** exponentdef format_result(self, result, precision=None, format_type='decimal'):"""格式化结果 - 使用关键字参数模拟重载"""if format_type == 'decimal':if precision is not None:return f"{result:.{precision}f}"else:return str(result)elif format_type == 'scientific':if precision is not None:return f"{result:.{precision}e}"else:return f"{result:e}"elif format_type == 'percentage':if precision is not None:return f"{result*100:.{precision}f}%"else:return f"{result*100:.2f}%"else:return str(result)# 方法重载模拟演示
print("\n=== 方法重载模拟演示 ===")calc = Calculator()print("加法方法的多种用法:")
print(f" add(): {calc.add()}")
print(f" add(5): {calc.add(5)}")
print(f" add(3, 7): {calc.add(3, 7)}")
print(f" add(1, 2, 3, 4, 5): {calc.add(1, 2, 3, 4, 5)}")
print(f" add([1, 2, 3, 4]): {calc.add([1, 2, 3, 4])}")print("\n乘法方法的多种用法:")
print(f" multiply(): {calc.multiply()}")
print(f" multiply(5): {calc.multiply(5)}")
print(f" multiply(3, 4): {calc.multiply(3, 4)}")
print(f" multiply(2, 3, 4): {calc.multiply(2, 3, 4)}")
print(f" multiply([2, 3, 4]): {calc.multiply([2, 3, 4])}")print("\n通用计算方法:")
print(f" calculate('add', 10, 20): {calc.calculate('add', 10, 20)}")
print(f" calculate('multiply', 3, 4, 5): {calc.calculate('multiply', 3, 4, 5)}")
print(f" calculate('subtract', 100, 30, 20): {calc.calculate('subtract', 100, 30, 20)}")
print(f" calculate('divide', 15, 3): {calc.calculate('divide', 15, 3)}")print("\n幂运算的默认参数:")
print(f" power(3): {calc.power(3)}")
print(f" power(3, 3): {calc.power(3, 3)}")
print(f" power(2, 10): {calc.power(2, 10)}")print("\n结果格式化:")
result = 3.14159265359
print(f" 原始结果: {result}")
print(f" 默认格式: {calc.format_result(result)}")
print(f" 2位小数: {calc.format_result(result, precision=2)}")
print(f" 科学计数法: {calc.format_result(result, format_type='scientific', precision=3)}")
print(f" 百分比格式: {calc.format_result(0.1234, format_type='percentage', precision=1)}")
属性与方法的访问控制
Python使用命名约定来实现访问控制,包括公共、受保护和私有属性。
1. 访问控制演示
class BankAccount:"""银行账户类 - 演示访问控制"""# 类变量(公共)bank_name = "Python银行"# 类变量(受保护)_interest_rate = 0.03# 类变量(私有)__bank_code = "PY001"def __init__(self, account_holder, initial_balance=0):# 公共属性self.account_holder = account_holder# 受保护属性(约定:仅在类内部和子类中使用)self._account_number = self._generate_account_number()self._creation_date = self._get_current_date()# 私有属性(名称改写:_ClassName__attribute)self.__balance = initial_balanceself.__pin = self._generate_pin()self.__transaction_history = []# 记录开户交易self.__add_transaction("开户", initial_balance)# 公共方法def get_account_info(self):"""获取账户基本信息(公共方法)"""return {"account_holder": self.account_holder,"account_number": self._account_number,"bank_name": self.bank_name,"creation_date": self._creation_date}def deposit(self, amount, pin):"""存款(公共方法)"""if not self._verify_pin(pin):raise ValueError("PIN码错误")if amount <= 0:raise ValueError("存款金额必须大于0")self.__balance += amountself.__add_transaction("存款", amount)return f"存款成功!当前余额: ¥{self.__balance:.2f}"def withdraw(self, amount, pin):"""取款(公共方法)"""if not self._verify_pin(pin):raise ValueError("PIN码错误")if amount <= 0:raise ValueError("取款金额必须大于0")if amount > self.__balance:raise ValueError("余额不足")self.__balance -= amountself.__add_transaction("取款", -amount)return f"取款成功!当前余额: ¥{self.__balance:.2f}"def get_balance(self, pin):"""查询余额(公共方法)"""if not self._verify_pin(pin):raise ValueError("PIN码错误")return self.__balance# 受保护方法(约定:仅在类内部和子类中使用)def _generate_account_number(self):"""生成账户号码(受保护方法)"""import randomreturn f"ACC{random.randint(100000, 999999)}"def _generate_pin(self):"""生成PIN码(受保护方法)"""import randomreturn f"{random.randint(1000, 9999)}"def _get_current_date(self):"""获取当前日期(受保护方法)"""from datetime import datetimereturn datetime.now().strftime("%Y-%m-%d")def _verify_pin(self, pin):"""验证PIN码(受保护方法)"""return str(pin) == self.__pindef _calculate_interest(self):"""计算利息(受保护方法)"""return self.__balance * self._interest_rate# 私有方法(名称改写)def __add_transaction(self, transaction_type, amount):"""添加交易记录(私有方法)"""from datetime import datetimetransaction = {"type": transaction_type,"amount": amount,"balance": self.__balance,"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")}self.__transaction_history.append(transaction)def __validate_transaction(self, amount, transaction_type):"""验证交易(私有方法)"""if transaction_type == "取款" and amount > self.__balance:return False, "余额不足"if amount <= 0:return False, "金额必须大于0"return True, "验证通过"# 属性装饰器(提供受控访问)@propertydef account_number(self):"""账户号码属性(只读)"""return self._account_number@propertydef creation_date(self):"""创建日期属性(只读)"""return self._creation_date# 管理员方法(用于演示私有属性访问)def admin_get_full_info(self, admin_password):"""管理员获取完整信息"""if admin_password != "admin123":raise ValueError("管理员密码错误")return {"account_holder": self.account_holder,"account_number": self._account_number,"balance": self.__balance,"pin": self.__pin,"transaction_count": len(self.__transaction_history),"bank_code": self.__bank_code}def admin_reset_pin(self, admin_password, new_pin):"""管理员重置PIN码"""if admin_password != "admin123":raise ValueError("管理员密码错误")if len(str(new_pin)) != 4:raise ValueError("PIN码必须是4位数字")old_pin = self.__pinself.__pin = str(new_pin)self.__add_transaction("PIN重置", 0)return f"PIN码已从{old_pin}重置为{new_pin}"def __str__(self):return f"BankAccount({self.account_holder}, {self._account_number})"def __repr__(self):return f"BankAccount('{self.account_holder}', {self.__balance})"# 访问控制演示
print("\n=== 访问控制演示 ===")# 创建账户
account = BankAccount("张三", 1000)print("=== 公共属性和方法 ===")
print(f"账户持有人: {account.account_holder}")
print(f"银行名称: {account.bank_name}")
print(f"账户信息: {account.get_account_info()}")# 使用属性装饰器
print(f"账户号码(属性): {account.account_number}")
print(f"创建日期(属性): {account.creation_date}")print("\n=== 受保护属性访问 ===")
print(f"账户号码(受保护): {account._account_number}")
print(f"利率(受保护): {account._interest_rate}")
print(f"创建日期(受保护): {account._creation_date}")print("\n=== 私有属性访问尝试 ===")
try:# 直接访问私有属性会失败print(f"余额(私有): {account.__balance}")
except AttributeError as e:print(f"无法直接访问私有属性: {e}")# 通过名称改写访问私有属性(不推荐)
print(f"余额(通过名称改写): {account._BankAccount__balance}")
print(f"PIN码(通过名称改写): {account._BankAccount__pin}")print("\n=== 正确的访问方式 ===")
# 获取PIN码进行操作
pin = account._BankAccount__pin # 仅用于演示
print(f"当前余额: ¥{account.get_balance(pin):.2f}")
print(account.deposit(500, pin))
print(account.withdraw(200, pin))print("\n=== 管理员功能 ===")
try:admin_info = account.admin_get_full_info("admin123")print(f"管理员查看完整信息: {admin_info}")print(account.admin_reset_pin("admin123", 5678))
except ValueError as e:print(f"管理员操作失败: {e}")print("\n=== 访问控制总结 ===")
print("""
访问控制约定:
1. 公共 (public): 正常命名,可以自由访问
2. 受保护 (protected): 以单下划线开头,约定仅在类内部和子类中使用
3. 私有 (private): 以双下划线开头,Python会进行名称改写注意: Python的访问控制主要依靠约定,技术上仍可以访问"私有"属性
""")
特殊方法(魔术方法)
Python中的特殊方法(也称为魔术方法或双下划线方法)允许类定义特殊行为。
1. 常用特殊方法演示
class Book:"""图书类 - 演示特殊方法"""def __init__(self, title, author, pages, price):"""构造方法"""self.title = titleself.author = authorself.pages = pagesself.price = priceself.is_borrowed = Falsedef __str__(self):"""字符串表示(用户友好)"""status = "已借出" if self.is_borrowed else "可借阅"return f"《{self.title}》- {self.author} ({status})"def __repr__(self):"""官方字符串表示(开发者友好)"""return f"Book('{self.title}', '{self.author}', {self.pages}, {self.price})"def __len__(self):"""返回页数(支持len()函数)"""return self.pagesdef __eq__(self, other):"""相等比较"""if not isinstance(other, Book):return Falsereturn (self.title == other.title and self.author == other.author)def __lt__(self, other):"""小于比较(按价格)"""if not isinstance(other, Book):return NotImplementedreturn self.price < other.pricedef __le__(self, other):"""小于等于比较"""return self < other or self == otherdef __gt__(self, other):"""大于比较"""if not isinstance(other, Book):return NotImplementedreturn self.price > other.pricedef __ge__(self, other):"""大于等于比较"""return self > other or self == otherdef __add__(self, other):"""加法操作(合并页数)"""if isinstance(other, Book):combined_title = f"{self.title} & {other.title}"combined_author = f"{self.author} & {other.author}"combined_pages = self.pages + other.pagescombined_price = self.price + other.pricereturn Book(combined_title, combined_author, combined_pages, combined_price)elif isinstance(other, (int, float)):# 增加页数return Book(self.title, self.author, self.pages + other, self.price)return NotImplementeddef __mul__(self, other):"""乘法操作(复制书籍)"""if isinstance(other, int):return [Book(self.title, self.author, self.pages, self.price) for _ in range(other)]return NotImplementeddef __contains__(self, keyword):"""成员测试(支持in操作符)"""keyword = keyword.lower()return (keyword in self.title.lower() or keyword in self.author.lower())def __getitem__(self, key):"""索引访问"""if key == 0 or key == 'title':return self.titleelif key == 1 or key == 'author':return self.authorelif key == 2 or key == 'pages':return self.pageselif key == 3 or key == 'price':return self.priceelse:raise KeyError(f"无效的键: {key}")def __setitem__(self, key, value):"""索引赋值"""if key == 0 or key == 'title':self.title = valueelif key == 1 or key == 'author':self.author = valueelif key == 2 or key == 'pages':self.pages = valueelif key == 3 or key == 'price':self.price = valueelse:raise KeyError(f"无效的键: {key}")def __call__(self, action='info'):"""使对象可调用"""if action == 'info':return f"书名: {self.title}, 作者: {self.author}, 页数: {self.pages}, 价格: ¥{self.price}"elif action == 'borrow':if not self.is_borrowed:self.is_borrowed = Truereturn f"《{self.title}》借阅成功"else:return f"《{self.title}》已被借出"elif action == 'return':if self.is_borrowed:self.is_borrowed = Falsereturn f"《{self.title}》归还成功"else:return f"《{self.title}》未被借出"else:return f"不支持的操作: {action}"def __hash__(self):"""哈希值(使对象可以作为字典键或集合元素)"""return hash((self.title, self.author))def __bool__(self):"""布尔值转换"""return not self.is_borrowed # 可借阅时为Truedef __del__(self):"""析构方法"""print(f"图书《{self.title}》被销毁")class Library:"""图书馆类 - 演示容器特殊方法"""def __init__(self, name):self.name = nameself.books = []self.current_index = 0def add_book(self, book):"""添加图书"""self.books.append(book)def __len__(self):"""返回图书数量"""return len(self.books)def __getitem__(self, index):"""支持索引访问"""return self.books[index]def __setitem__(self, index, book):"""支持索引赋值"""self.books[index] = bookdef __delitem__(self, index):"""支持索引删除"""del self.books[index]def __contains__(self, item):"""支持成员测试"""if isinstance(item, Book):return item in self.bookselif isinstance(item, str):# 按书名或作者搜索return any(item.lower() in book.title.lower() or item.lower() in book.author.lower() for book in self.books)return Falsedef __iter__(self):"""支持迭代"""return iter(self.books)def __next__(self):"""迭代器协议"""if self.current_index >= len(self.books):self.current_index = 0raise StopIterationbook = self.books[self.current_index]self.current_index += 1return bookdef __str__(self):available_count = sum(1 for book in self.books if not book.is_borrowed)return f"{self.name} - 总藏书: {len(self.books)}, 可借阅: {available_count}"def __repr__(self):return f"Library('{self.name}', {len(self.books)} books)"# 特殊方法演示
print("=== 特殊方法演示 ===")# 创建图书
book1 = Book("Python编程", "张三", 300, 59.9)
book2 = Book("数据结构", "李四", 400, 69.9)
book3 = Book("算法导论", "王五", 500, 89.9)
book4 = Book("Python编程", "张三", 300, 59.9) # 与book1相同print("=== 字符串表示 ===")
print(f"str(book1): {str(book1)}")
print(f"repr(book1): {repr(book1)}")print("\n=== 长度和比较 ===")
print(f"len(book1): {len(book1)} 页")
print(f"book1 == book4: {book1 == book4}")
print(f"book1 < book2: {book1 < book2}")
print(f"book2 > book1: {book2 > book1}")print("\n=== 算术运算 ===")
combined_book = book1 + book2
print(f"合并图书: {combined_book}")
print(f"增加页数: {book1 + 50}")book_copies = book1 * 3
print(f"复制图书: {len(book_copies)} 本")print("\n=== 成员测试 ===")
print(f"'Python' in book1: {'Python' in book1}")
print(f"'Java' in book1: {'Java' in book1}")print("\n=== 索引访问 ===")
print(f"book1[0]: {book1[0]}")
print(f"book1['author']: {book1['author']}")
book1['price'] = 49.9
print(f"修改价格后: {book1['price']}")print("\n=== 可调用对象 ===")
print(book1()) # 默认info
print(book1('borrow'))
print(book1('borrow')) # 再次借阅
print(book1('return'))print("\n=== 布尔值转换 ===")
print(f"bool(book1): {bool(book1)}")
book1('borrow')
print(f"借出后 bool(book1): {bool(book1)}")
book1('return')print("\n=== 哈希值和集合操作 ===")
book_set = {book1, book2, book3, book4}
print(f"图书集合大小: {len(book_set)}")
print(f"book1的哈希值: {hash(book1)}")
print(f"book4的哈希值: {hash(book4)}")print("\n=== 图书馆容器演示 ===")
library = Library("Python学习图书馆")
library.add_book(book1)
library.add_book(book2)
library.add_book(book3)print(f"图书馆信息: {library}")
print(f"图书馆藏书数量: {len(library)}")
print(f"第一本书: {library[0]}")
print(f"是否有Python相关书籍: {'Python' in library}")print("\n遍历图书馆:")
for book in library:print(f" {book}")print("\n=== 排序演示 ===")
books = [book1, book2, book3]
books_sorted = sorted(books) # 按价格排序
print("按价格排序:")
for book in books_sorted:print(f" {book} - ¥{book.price}")
2. 特殊方法总结
class SpecialMethodsDemo:"""特殊方法总结和分类"""def __init__(self):print("=== Python特殊方法分类 ===")self.categories = {"对象创建和销毁": ["__new__: 创建实例","__init__: 初始化实例","__del__: 销毁实例"],"字符串表示": ["__str__: 用户友好的字符串表示","__repr__: 开发者友好的字符串表示","__format__: 格式化字符串"],"数值运算": ["__add__, __sub__, __mul__, __div__: 基本算术运算","__pow__, __mod__, __divmod__: 幂运算、取模、除法取整","__and__, __or__, __xor__: 位运算","__lshift__, __rshift__: 位移运算"],"比较运算": ["__eq__, __ne__: 相等、不等","__lt__, __le__, __gt__, __ge__: 大小比较"],"容器操作": ["__len__: 长度","__getitem__, __setitem__, __delitem__: 索引操作","__contains__: 成员测试 (in)","__iter__, __next__: 迭代器协议"],"类型转换": ["__bool__: 布尔值转换","__int__, __float__, __complex__: 数值类型转换","__hash__: 哈希值"],"属性访问": ["__getattr__, __setattr__, __delattr__: 属性访问控制","__getattribute__: 属性访问拦截"],"函数调用": ["__call__: 使对象可调用"],"上下文管理": ["__enter__, __exit__: 上下文管理器协议 (with语句)"]}def show_categories(self):"""显示特殊方法分类"""for category, methods in self.categories.items():print(f"\n{category}:")for method in methods:print(f" • {method}")def show_usage_tips(self):"""显示使用建议"""print("\n=== 特殊方法使用建议 ===")tips = ["1. 总是实现 __str__ 和 __repr__,提供有意义的字符串表示","2. 实现比较方法时,考虑使用 functools.total_ordering 装饰器","3. 实现 __hash__ 时,确保与 __eq__ 保持一致","4. 容器类应该实现 __len__, __getitem__, __iter__ 等方法","5. 算术运算方法应该返回新对象,而不是修改原对象","6. 使用 NotImplemented 而不是 NotImplementedError 来处理不支持的操作","7. __bool__ 方法应该返回有意义的布尔值","8. 谨慎实现 __del__,避免循环引用问题"]for tip in tips:print(f" {tip}")# 显示特殊方法总结
demo = SpecialMethodsDemo()
demo.show_categories()
demo.show_usage_tips()
总结
面向对象编程是Python的核心特性之一,通过本章的学习,我们掌握了:
核心概念
- 类与对象:类是对象的模板,对象是类的实例
- 封装:将数据和方法组织在一起,控制访问权限
- 继承:子类继承父类的属性和方法,实现代码复用
- 多态:同一接口的不同实现,提高代码的灵活性
重要特性
- 构造方法:
__init__
用于初始化对象 - 方法重写:子类可以重写父类的方法
- 访问控制:使用命名约定控制属性和方法的访问权限
- 特殊方法:定义对象的特殊行为,如字符串表示、运算符重载等
最佳实践
- 合理设计类的层次结构,避免过深的继承链
- 遵循单一职责原则,每个类只负责一个功能
- 使用组合优于继承,在适当的时候选择组合
- 提供清晰的接口,隐藏实现细节
- 编写文档字符串,说明类和方法的用途
- 实现必要的特殊方法,使对象行为更自然
应用场景
- 数据建模:用类表示现实世界的实体
- 代码组织:将相关的数据和功能组织在一起
- 框架开发:提供可扩展的基础结构
- 设计模式:实现各种设计模式
面向对象编程不仅是一种编程范式,更是一种思维方式。通过合理运用OOP的概念和技术,我们可以编写出更加模块化、可维护和可扩展的代码。
本章介绍了Python面向对象编程的核心概念和实践技巧。下一章我们将学习异常处理,了解如何优雅地处理程序中的错误和异常情况。