面向对象编程(OOP)
面向对象编程是一种编程范式,它使用"对象"来设计应用程序和计算机程序。Python是一种面向对象的编程语言,支持封装、继承和多态等核心概念。
scss
面向对象编程核心概念图:
┌─────────────────────────────────────────────┐
│ 面向对象编程 │
├─────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 封装 │ │ 继承 │ │ 多态 │ │
│ │Encap- │ │Inherit- │ │Polymor- │ │
│ │sulation │ │ance │ │phism │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 隐藏实现 代码重用 统一接口 │
│ 数据保护 扩展功能 灵活调用 │
│ │
└─────────────────────────────────────────────┘
类与对象
类是对象的蓝图或模板,对象是类的实例。
1. 类的定义与实例化
python
# 定义一个简单的类
class Person:
"""人员类"""
# 类变量(所有实例共享)
species = "Homo sapiens"
population = 0
def __init__(self, name, age):
"""构造方法(初始化方法)"""
# 实例变量(每个实例独有)
self.name = name
self.age = age
Person.population += 1 # 增加人口计数
def introduce(self):
"""自我介绍方法"""
return f"你好,我是{self.name},今年{self.age}岁"
def have_birthday(self):
"""过生日,年龄增加1"""
self.age += 1
return 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. 类变量与实例变量
python
class BankAccount:
"""银行账户类"""
# 类变量
bank_name = "Python银行"
interest_rate = 0.03 # 3%年利率
total_accounts = 0
def __init__(self, account_holder, initial_balance=0):
"""初始化账户"""
# 实例变量
self.account_holder = account_holder
self.balance = initial_balance
self.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 datetime
transaction = {
"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 += amount
self._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 -= amount
self._add_transaction("取款", -amount)
return f"取款成功!当前余额: ¥{self.balance:.2f}"
def get_balance(self):
"""查询余额"""
return self.balance
def calculate_interest(self):
"""计算利息"""
interest = self.balance * self.interest_rate
return interest
def apply_interest(self):
"""应用利息"""
interest = self.calculate_interest()
self.balance += interest
self._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}")
@classmethod
def get_bank_info(cls):
"""类方法:获取银行信息"""
return {
"bank_name": cls.bank_name,
"total_accounts": cls.total_accounts,
"interest_rate": cls.interest_rate
}
@classmethod
def set_interest_rate(cls, new_rate):
"""类方法:设置利率"""
if new_rate < 0:
raise ValueError("利率不能为负数")
cls.interest_rate = new_rate
return f"利率已更新为 {new_rate*100:.2f}%"
@staticmethod
def calculate_compound_interest(principal, rate, time):
"""静态方法:计算复利"""
return principal * (1 + rate) ** time
def __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. 基本构造方法
python
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 = name
self.student_id = student_id
self.major = major
self.year = year
self.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"] = grade
self.grades[course_name] = grade
self._calculate_gpa()
return f"{course_name} 成绩已录入: {grade}分"
raise ValueError(f"未找到课程: {course_name}")
def _calculate_gpa(self):
"""私有方法:计算GPA"""
if not self.grades:
self.gpa = 0.0
return
total_points = 0
total_credits = 0
for 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.0
grade = course["grade"]
if grade >= 90:
points = 4.0
elif grade >= 80:
points = 3.0
elif grade >= 70:
points = 2.0
elif grade >= 60:
points = 1.0
else:
points = 0.0
total_points += points * course["credits"]
total_credits += course["credits"]
self.gpa = total_points / total_credits if total_credits > 0 else 0.0
def 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 transcript
def 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. 多种初始化方式
python
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 = args
elif '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.height
def perimeter(self):
"""计算周长"""
return 2 * (self.width + self.height)
def is_square(self):
"""判断是否为正方形"""
return self.width == self.height
def scale(self, factor):
"""缩放矩形"""
self.width *= factor
self.height *= factor
return self
def __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 False
return self.width == other.width and self.height == other.height
def __lt__(self, other):
"""小于比较(按面积)"""
if not isinstance(other, Rectangle):
return NotImplemented
return 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. 实例方法、类方法和静态方法
python
class MathUtils:
"""数学工具类,演示不同类型的方法"""
# 类变量
pi = 3.14159265359
calculation_count = 0
def __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 += 1
return result
def calculate_circle_area(self, radius):
"""实例方法:计算圆面积"""
area = self.pi * radius ** 2
result = self.round_number(area)
self.history.append(f"circle_area(r={radius}) = {result}")
return result
def get_history(self):
"""实例方法:获取计算历史"""
return self.history.copy()
def clear_history(self):
"""实例方法:清空计算历史"""
self.history.clear()
return "计算历史已清空"
# 类方法(需要cls参数,使用@classmethod装饰器)
@classmethod
def get_calculation_count(cls):
"""类方法:获取总计算次数"""
return cls.calculation_count
@classmethod
def reset_calculation_count(cls):
"""类方法:重置计算次数"""
cls.calculation_count = 0
return "计算次数已重置"
@classmethod
def set_pi(cls, new_pi):
"""类方法:设置π的值"""
if new_pi <= 0:
raise ValueError("π必须大于0")
old_pi = cls.pi
cls.pi = new_pi
return f"π已从{old_pi}更新为{new_pi}"
@classmethod
def create_high_precision(cls):
"""类方法:创建高精度实例"""
return cls(precision=6)
@classmethod
def create_low_precision(cls):
"""类方法:创建低精度实例"""
return cls(precision=0)
# 静态方法(不需要self或cls参数,使用@staticmethod装饰器)
@staticmethod
def is_even(number):
"""静态方法:判断是否为偶数"""
return number % 2 == 0
@staticmethod
def is_prime(n):
"""静态方法:判断是否为质数"""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True
@staticmethod
def factorial(n):
"""静态方法:计算阶乘"""
if n < 0:
raise ValueError("阶乘的参数必须是非负整数")
if n == 0 or n == 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
@staticmethod
def gcd(a, b):
"""静态方法:计算最大公约数"""
while b:
a, b = b, a % b
return abs(a)
@staticmethod
def convert_temperature(temp, from_unit, to_unit):
"""静态方法:温度转换"""
# 先转换为摄氏度
if from_unit.lower() == 'f':
celsius = (temp - 32) * 5/9
elif from_unit.lower() == 'k':
celsius = temp - 273.15
else:
celsius = temp
# 再转换为目标单位
if to_unit.lower() == 'f':
return celsius * 9/5 + 32
elif to_unit.lower() == 'k':
return celsius + 273.15
else:
return celsius
def __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. 方法类型的选择指南
python
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}"
# 类方法:需要访问类数据或创建实例时使用
@classmethod
def class_method(cls):
"""
使用类方法的情况:
1. 需要访问或修改类变量
2. 创建实例的替代构造器
3. 操作与类相关但不依赖实例的数据
"""
return f"类方法访问类变量: {cls.class_variable}"
@classmethod
def alternative_constructor(cls, data_string):
"""替代构造器示例"""
# 解析字符串并创建实例
processed_data = data_string.upper()
return cls(processed_data)
# 静态方法:与类相关但不需要访问类或实例数据时使用
@staticmethod
def 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. 基本继承
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):
"""吃东西"""
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 = breed
self.owner = owner
self.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 = breed
self.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_fly
self.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 += distance
return 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. 多重继承
python
# 多重继承示例
class Flyable:
"""可飞行的混入类"""
def __init__(self):
self.altitude = 0
self.max_altitude = 1000
def take_off(self):
"""起飞"""
if self.altitude == 0:
self.altitude = 10
return f"{getattr(self, 'name', '飞行器')}起飞了,当前高度:{self.altitude}米"
return f"{getattr(self, 'name', '飞行器')}已经在飞行中"
def land(self):
"""降落"""
if self.altitude > 0:
self.altitude = 0
return f"{getattr(self, 'name', '飞行器')}降落了"
return f"{getattr(self, 'name', '飞行器')}已经在地面上"
def change_altitude(self, delta):
"""改变高度"""
new_altitude = self.altitude + delta
if new_altitude < 0:
new_altitude = 0
elif new_altitude > self.max_altitude:
new_altitude = self.max_altitude
old_altitude = self.altitude
self.altitude = new_altitude
if 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 = 0
self.max_depth = 100
def dive(self, target_depth):
"""潜水"""
if target_depth > self.max_depth:
target_depth = self.max_depth
old_depth = self.depth
self.depth = target_depth
if 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 = 0
return 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. 多态演示
python
# 多态演示
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. 方法重写
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}"
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 = radius
def area(self):
"""重写area方法"""
import math
return math.pi * self.radius ** 2
def perimeter(self):
"""重写perimeter方法"""
import math
return 2 * math.pi * self.radius
def describe(self):
"""重写describe方法,添加更多信息"""
base_desc = super().describe()
return f"{base_desc},半径为{self.radius}"
def diameter(self):
"""圆形特有的方法"""
return 2 * self.radius
def __str__(self):
return f"Circle(radius={self.radius})"
class Rectangle(Shape):
"""矩形类"""
def __init__(self, width, height):
super().__init__("矩形")
self.width = width
self.height = height
def area(self):
"""重写area方法"""
return self.width * self.height
def 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.height
def diagonal(self):
"""计算对角线长度"""
import math
return 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 = a
self.b = b
self.c = c
def area(self):
"""重写area方法 - 使用海伦公式"""
import math
s = 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.c
def 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. 模拟方法重载
python
class Calculator:
"""计算器类,演示Python中的方法重载模拟"""
def add(self, *args, **kwargs):
"""加法方法 - 支持多种参数形式"""
if len(args) == 0:
return 0
elif len(args) == 1:
# 单个参数:可能是数字或列表
arg = args[0]
if isinstance(arg, (list, tuple)):
return sum(arg)
else:
return arg
elif len(args) == 2:
# 两个参数:普通加法
return args[0] + args[1]
else:
# 多个参数:全部相加
return sum(args)
def multiply(self, *args, **kwargs):
"""乘法方法 - 支持多种参数形式"""
if len(args) == 0:
return 1
elif len(args) == 1:
arg = args[0]
if isinstance(arg, (list, tuple)):
result = 1
for num in arg:
result *= num
return result
else:
return arg
else:
result = 1
for num in args:
result *= num
return result
def 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 -= num
return result
elif 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 ** exponent
def 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. 访问控制演示
python
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_balance
self.__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 += amount
self.__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 -= amount
self.__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 random
return f"ACC{random.randint(100000, 999999)}"
def _generate_pin(self):
"""生成PIN码(受保护方法)"""
import random
return f"{random.randint(1000, 9999)}"
def _get_current_date(self):
"""获取当前日期(受保护方法)"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d")
def _verify_pin(self, pin):
"""验证PIN码(受保护方法)"""
return str(pin) == self.__pin
def _calculate_interest(self):
"""计算利息(受保护方法)"""
return self.__balance * self._interest_rate
# 私有方法(名称改写)
def __add_transaction(self, transaction_type, amount):
"""添加交易记录(私有方法)"""
from datetime import datetime
transaction = {
"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, "验证通过"
# 属性装饰器(提供受控访问)
@property
def account_number(self):
"""账户号码属性(只读)"""
return self._account_number
@property
def 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.__pin
self.__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. 常用特殊方法演示
python
class Book:
"""图书类 - 演示特殊方法"""
def __init__(self, title, author, pages, price):
"""构造方法"""
self.title = title
self.author = author
self.pages = pages
self.price = price
self.is_borrowed = False
def __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.pages
def __eq__(self, other):
"""相等比较"""
if not isinstance(other, Book):
return False
return (self.title == other.title and
self.author == other.author)
def __lt__(self, other):
"""小于比较(按价格)"""
if not isinstance(other, Book):
return NotImplemented
return self.price < other.price
def __le__(self, other):
"""小于等于比较"""
return self < other or self == other
def __gt__(self, other):
"""大于比较"""
if not isinstance(other, Book):
return NotImplemented
return self.price > other.price
def __ge__(self, other):
"""大于等于比较"""
return self > other or self == other
def __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.pages
combined_price = self.price + other.price
return 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 NotImplemented
def __mul__(self, other):
"""乘法操作(复制书籍)"""
if isinstance(other, int):
return [Book(self.title, self.author, self.pages, self.price)
for _ in range(other)]
return NotImplemented
def __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.title
elif key == 1 or key == 'author':
return self.author
elif key == 2 or key == 'pages':
return self.pages
elif key == 3 or key == 'price':
return self.price
else:
raise KeyError(f"无效的键: {key}")
def __setitem__(self, key, value):
"""索引赋值"""
if key == 0 or key == 'title':
self.title = value
elif key == 1 or key == 'author':
self.author = value
elif key == 2 or key == 'pages':
self.pages = value
elif key == 3 or key == 'price':
self.price = value
else:
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 = True
return f"《{self.title}》借阅成功"
else:
return f"《{self.title}》已被借出"
elif action == 'return':
if self.is_borrowed:
self.is_borrowed = False
return 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 # 可借阅时为True
def __del__(self):
"""析构方法"""
print(f"图书《{self.title}》被销毁")
class Library:
"""图书馆类 - 演示容器特殊方法"""
def __init__(self, name):
self.name = name
self.books = []
self.current_index = 0
def 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] = book
def __delitem__(self, index):
"""支持索引删除"""
del self.books[index]
def __contains__(self, item):
"""支持成员测试"""
if isinstance(item, Book):
return item in self.books
elif isinstance(item, str):
# 按书名或作者搜索
return any(item.lower() in book.title.lower() or
item.lower() in book.author.lower()
for book in self.books)
return False
def __iter__(self):
"""支持迭代"""
return iter(self.books)
def __next__(self):
"""迭代器协议"""
if self.current_index >= len(self.books):
self.current_index = 0
raise StopIteration
book = self.books[self.current_index]
self.current_index += 1
return book
def __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. 特殊方法总结
python
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面向对象编程的核心概念和实践技巧。下一章我们将学习异常处理,了解如何优雅地处理程序中的错误和异常情况。
更多精彩文章
