python基础-面向对象编程(OOP)

面向对象编程(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__ 用于初始化对象
  • 方法重写:子类可以重写父类的方法
  • 访问控制:使用命名约定控制属性和方法的访问权限
  • 特殊方法:定义对象的特殊行为,如字符串表示、运算符重载等

最佳实践

  1. 合理设计类的层次结构,避免过深的继承链
  2. 遵循单一职责原则,每个类只负责一个功能
  3. 使用组合优于继承,在适当的时候选择组合
  4. 提供清晰的接口,隐藏实现细节
  5. 编写文档字符串,说明类和方法的用途
  6. 实现必要的特殊方法,使对象行为更自然

应用场景

  • 数据建模:用类表示现实世界的实体
  • 代码组织:将相关的数据和功能组织在一起
  • 框架开发:提供可扩展的基础结构
  • 设计模式:实现各种设计模式

面向对象编程不仅是一种编程范式,更是一种思维方式。通过合理运用OOP的概念和技术,我们可以编写出更加模块化、可维护和可扩展的代码。


本章介绍了Python面向对象编程的核心概念和实践技巧。下一章我们将学习异常处理,了解如何优雅地处理程序中的错误和异常情况。

更多精彩文章

相关推荐
都是些老物件9 小时前
如何用熵正则化控制注意力分数的分布
开发语言·python
蒋星熠10 小时前
Redis 7.0 高性能缓存架构设计与优化
数据库·redis·分布式·python·缓存·docker·微服务
雷达学弱狗11 小时前
python反转字符串
开发语言·python
数据智能老司机12 小时前
精通文本分析——自然语言处理导论
python·nlp
日月晨曦12 小时前
LLM幻觉的终极解药:FunctionCall让AI从"胡说八道"变"实事求是"
python·llm
CaracalTiger13 小时前
网站漏洞早发现:cpolar+Web-Check安全扫描组合解决方案
java·开发语言·前端·python·安全·golang·wpf
是乐谷13 小时前
Python图片转WebP常用库推荐:Pillow、Wand、cv2
大数据·运维·开发语言·人工智能·python·开源·pillow
这里有鱼汤14 小时前
A股预测还能更准?开源大模型Kronos带你跑通预测+回测全流程
后端·python
大模型真好玩14 小时前
深入浅出LangGraph AI Agent智能体开发教程(二)—LangGraph预构建图API快速创建Agent
人工智能·python·mcp