适合人群:Python 初学者、编程爱好者、准备面试的开发者
难度:⭐⭐⭐☆☆
关键词:类、对象、封装、继承、多态、类方法、静态方法、构造方法、析构方法


目录

  1. 面向对象编程思想
  2. 类与对象的基本定义
  3. 构造方法与析构方法
  4. self 参数详解
  5. 类变量与实例变量
  6. 类方法与静态方法
  7. 封装与私有成员
  8. 单继承与多继承
  9. 方法重写与 super()
  10. 多态的实现
  11. 综合实战项目
  12. 常见面试题与总结

一、面向对象编程思想

1.1 什么是面向对象?

面向对象编程(OOP)是一种编程范式,它把数据操作数据的方法封装在一起,形成“对象”。现实世界中的任何事物都可以抽象为对象。

1.2 面向对象 vs 面向过程

对比维度 面向过程 面向对象
核心 函数/过程 类/对象
数据组织 数据结构独立于函数 数据和方法绑定在一起
代码复用 通过函数调用 通过继承、组合
扩展性 较差 较好
典型语言 C Java, Python, C++

二、类与对象的基本定义

2.1 定义一个最简单的类

class Dog:
    pass

# 创建对象
my_dog = Dog()
print(type(my_dog))  # <class '__main__.Dog'>

2.2 为类添加属性和方法

class Dog:
    # 类属性(所有实例共享)
    species = "Canis familiaris"
    
    # 实例方法
    def bark(self):
        print("汪汪!")

# 创建对象
dog1 = Dog()
dog2 = Dog()

# 访问类属性
print(dog1.species)  # Canis familiaris

# 调用方法
dog1.bark()  # 汪汪!

2.3 案例1:学生类

class Student:
    """学生类,包含姓名和成绩"""
    school = "第一中学"  # 类属性
    
    def study(self):
        print(f"{self.name} 正在学习")
    
    def get_score(self):
        return self.score

# 创建对象并动态添加属性
s1 = Student()
s1.name = "小明"
s1.score = 95
s1.study()  # 小明 正在学习
print(f"{s1.name} 的成绩是 {s1.get_score()}")  # 小明的成绩是 95

三、构造方法与析构方法

3.1 构造方法 __init__()

class Person:
    def __init__(self, name, age):
        print("构造方法被调用")
        self.name = name
        self.age = age
    
    def introduce(self):
        print(f"我叫{self.name},今年{self.age}岁")

# 创建对象时自动调用构造方法
p1 = Person("张三", 20)  # 构造方法被调用
p1.introduce()  # 我叫张三,今年20岁

3.2 构造方法的重载(Python不支持传统重载,但可设置默认值)

class Book:
    def __init__(self, title, author="未知作者", price=0.0):
        self.title = title
        self.author = author
        self.price = price
    
    def info(self):
        print(f"《{self.title}》- {self.author} - ¥{self.price}")

b1 = Book("Python入门")
b2 = Book("Python进阶", "李四")
b3 = Book("Python高级", "王五", 99.9)

b1.info()  # 《Python入门》- 未知作者 - ¥0.0
b2.info()  # 《Python进阶》- 李四 - ¥0.0
b3.info()  # 《Python高级》- 王五 - ¥99.9

3.3 析构方法 __del__()

class Resource:
    def __init__(self, name):
        self.name = name
        print(f"资源 {self.name} 已创建")
    
    def __del__(self):
        print(f"资源 {self.name} 已销毁")

# 创建对象
r1 = Resource("文件1")  # 资源 文件1 已创建
r2 = Resource("文件2")  # 资源 文件2 已创建

# 手动删除对象
del r1  # 资源 文件1 已销毁

print("程序结束")  
# 程序结束
# 资源 文件2 已销毁(程序结束时自动调用)

3.4 案例2:银行账户类(构造方法+析构方法)

class BankAccount:
    account_count = 0  # 统计账户数量
    
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
        BankAccount.account_count += 1
        print(f"欢迎 {owner},账户创建成功!当前余额:{balance}元")
    
    def deposit(self, amount):
        if amount > 0:
            self.balance += amount
            print(f"存入 {amount} 元,当前余额:{self.balance}元")
        else:
            print("存款金额必须大于0")
    
    def withdraw(self, amount):
        if amount > self.balance:
            print(f"余额不足!当前余额:{self.balance}元")
        elif amount <= 0:
            print("取款金额必须大于0")
        else:
            self.balance -= amount
            print(f"取出 {amount} 元,当前余额:{self.balance}元")
    
    def __del__(self):
        BankAccount.account_count -= 1
        print(f"账户 {self.owner} 已注销,剩余账户数:{BankAccount.account_count}")

# 测试
acc1 = BankAccount("张三", 1000)  # 欢迎 张三,账户创建成功!当前余额:1000元
acc1.deposit(500)   # 存入 500 元,当前余额:1500元
acc1.withdraw(200)  # 取出 200 元,当前余额:1300元
acc1.withdraw(2000) # 余额不足!当前余额:1300元

acc2 = BankAccount("李四")  # 欢迎 李四,账户创建成功!当前余额:0元
del acc1  # 账户 张三 已注销,剩余账户数:1

四、self 参数详解

4.1 self 的本质

self 代表当前对象本身,类似于 Java/C++ 中的 this

class Car:
    def __init__(self, brand):
        self.brand = brand
    
    def show(self):
        print(f"这辆车的品牌是 {self.brand}")
        print(f"当前对象的id: {id(self)}")

c1 = Car("特斯拉")
c2 = Car("比亚迪")

print(f"c1的id: {id(c1)}")  # c1的id: 140234567890
c1.show()  # 这辆车的品牌是 特斯拉,当前对象的id: 140234567890

print(f"c2的id: {id(c2)}")  # c2的id: 140234567999
c2.show()  # 这辆车的品牌是 比亚迪,当前对象的id: 140234567999

4.2 self 可以改名吗?

可以,但不建议这样做,会降低代码可读性。

class Demo:
    def method(this_object):  # 把 self 改成 this_object
        print(f"对象id: {id(this_object)}")

d = Demo()
d.method()  # 正常运行

五、类变量与实例变量

5.1 基本区别

类型 定义位置 访问方式 归属 共享性
类变量 类中方法外 类名或对象名 所有实例共享
实例变量 __init__() 只能用对象名 实例 各自独立

5.2 详细案例

class Employee:
    company = "科技有限公司"  # 类变量
    total_employees = 0      # 类变量,统计员工总数
    
    def __init__(self, name, salary):
        self.name = name      # 实例变量
        self.salary = salary  # 实例变量
        Employee.total_employees += 1
    
    def info(self):
        print(f"姓名:{self.name},薪资:{self.salary},公司:{Employee.company}")

# 创建员工
e1 = Employee("张三", 8000)
e2 = Employee("李四", 9000)

# 访问类变量
print(Employee.company)  # 科技有限公司
print(e1.company)        # 科技有限公司(通过实例访问类变量)
print(e2.company)        # 科技有限公司

# 修改类变量会影响所有实例
Employee.company = "新科技有限公司"
print(e1.company)  # 新科技有限公司
print(e2.company)  # 新科技有限公司

# 通过实例修改类变量?实际上创建了实例变量
e1.company = "个人工作室"  # 这是创建了一个实例变量,不是修改类变量
print(e1.company)  # 个人工作室(实例变量)
print(e2.company)  # 新科技有限公司(类变量)
print(Employee.company)  # 新科技有限公司(类变量)

# 员工总数
print(f"员工总数:{Employee.total_employees}")  # 员工总数:2

5.3 案例3:商品库存系统

class Product:
    category = "电子产品"  # 类变量
    total_products = 0    # 总商品数
    
    def __init__(self, name, price, stock):
        self.name = name      # 实例变量
        self.price = price    # 实例变量
        self.stock = stock    # 实例变量(库存)
        Product.total_products += 1
    
    def sell(self, quantity):
        if quantity <= self.stock:
            self.stock -= quantity
            print(f"售出 {quantity}{self.name},剩余库存:{self.stock}")
        else:
            print(f"库存不足!当前库存:{self.stock}")
    
    @classmethod
    def get_total_products(cls):
        return cls.total_products

# 创建商品
p1 = Product("手机", 2999, 50)
p2 = Product("平板", 1999, 30)
p3 = Product("耳机", 199, 100)

print(f"总商品种类:{Product.get_total_products()}")  # 总商品种类:3
print(f"商品类别:{p1.category}")  # 商品类别:电子产品

p1.sell(10)  # 售出 10 个 手机,剩余库存:40
p2.sell(35)  # 库存不足!当前库存:30

六、类方法与静态方法

6.1 类方法(@classmethod)

  • 第一个参数是 cls(类本身)
  • 可以访问和修改类变量
  • 可以通过类名或实例调用
class Temperature:
    _base_freeze = 0  # 摄氏度的冰点
    _base_boil = 100  # 摄氏度的沸点
    
    @classmethod
    def celsius_to_fahrenheit(cls, celsius):
        """摄氏转华氏"""
        return celsius * 9/5 + 32
    
    @classmethod
    def fahrenheit_to_celsius(cls, fahrenheit):
        """华氏转摄氏"""
        return (fahrenheit - 32) * 5/9
    
    @classmethod
    def get_water_state(cls, celsius):
        """根据温度返回水的状态"""
        if celsius <= cls._base_freeze:
            return "固态(冰)"
        elif celsius >= cls._base_boil:
            return "气态(水蒸气)"
        else:
            return "液态(水)"

# 直接通过类名调用类方法
print(Temperature.celsius_to_fahrenheit(25))  # 77.0
print(Temperature.fahrenheit_to_celsius(77))  # 25.0
print(Temperature.get_water_state(-5))  # 固态(冰)
print(Temperature.get_water_state(25))  # 液态(水)
print(Temperature.get_water_state(105)) # 气态(水蒸气)

6.2 静态方法(@staticmethod)

  • 没有 selfcls 参数
  • 不能访问类变量或实例变量
  • 类似于普通函数,但放在类中作为逻辑分组
class MathUtils:
    """数学工具类"""
    
    @staticmethod
    def is_prime(n):
        """判断是否为质数"""
        if n < 2:
            return False
        for i in range(2, int(n ** 0.5) + 1):
            if n % i == 0:
                return False
        return True
    
    @staticmethod
    def factorial(n):
        """计算阶乘"""
        if n == 0:
            return 1
        result = 1
        for i in range(1, n + 1):
            result *= i
        return result
    
    @staticmethod
    def gcd(a, b):
        """计算最大公约数(欧几里得算法)"""
        while b:
            a, b = b, a % b
        return a

# 调用静态方法
print(MathUtils.is_prime(17))   # True
print(MathUtils.is_prime(20))   # False
print(MathUtils.factorial(5))   # 120
print(MathUtils.gcd(48, 18))    # 6

6.3 三种方法的对比案例

class MyClass:
    class_var = 10  # 类变量
    
    def __init__(self, value):
        self.instance_var = value  # 实例变量
    
    def instance_method(self):
        """实例方法:可以访问实例变量和类变量"""
        print(f"实例方法:instance_var={self.instance_var}, class_var={self.class_var}")
    
    @classmethod
    def class_method(cls):
        """类方法:只能访问类变量,不能访问实例变量"""
        print(f"类方法:class_var={cls.class_var}")
        # print(cls.instance_var)  # 报错!
    
    @staticmethod
    def static_method():
        """静态方法:不能访问实例变量和类变量"""
        print("静态方法:这是一个独立的函数")
        # print(class_var)  # 报错!

# 使用示例
obj = MyClass(100)

obj.instance_method()  # 实例方法:instance_var=100, class_var=10
obj.class_method()     # 类方法:class_var=10
obj.static_method()    # 静态方法:这是一个独立的函数

MyClass.class_method()  # 也可以通过类名调用类方法
MyClass.static_method() # 也可以通过类名调用静态方法

七、封装与私有成员

7.1 私有属性和方法

Python 中使用双下划线 __ 前缀来表示私有成员。

class Bank:
    def __init__(self, name, balance):
        self.name = name
        self.__balance = balance  # 私有属性
        self.__password = "123456"  # 私有属性
    
    def __secret_method(self):  # 私有方法
        return "这是内部方法"
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"存款成功,当前余额:{self.__balance}")
        else:
            print("存款金额无效")
    
    def withdraw(self, amount, password):
        if password != self.__password:
            print("密码错误")
            return
        if amount > self.__balance:
            print("余额不足")
        else:
            self.__balance -= amount
            print(f"取款成功,当前余额:{self.__balance}")
    
    def get_balance(self):
        """提供安全的访问接口"""
        return self.__balance

# 测试
acc = Bank("张三", 1000)
acc.deposit(500)      # 存款成功,当前余额:1500

# 直接访问私有属性会报错
# print(acc.__balance)  # AttributeError

# 通过接口访问
print(acc.get_balance())  # 1500

# 通过 _类名__属性 可以强制访问(不推荐)
print(acc._Bank__balance)  # 1500(伪私有)

7.2 使用 property 实现属性控制

class Student:
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    
    @property
    def score(self):
        """获取分数"""
        return self.__score
    
    @score.setter
    def score(self, value):
        """设置分数,带验证"""
        if 0 <= value <= 100:
            self.__score = value
        else:
            raise ValueError("分数必须在0-100之间")
    
    @score.deleter
    def score(self):
        """删除分数"""
        print("删除分数")
        del self.__score

# 使用
s = Student("小明", 85)
print(s.score)  # 85(像访问属性一样调用getter)

s.score = 95    # 调用setter
print(s.score)  # 95

# s.score = 101  # ValueError: 分数必须在0-100之间

7.3 案例4:员工管理系统(封装实践)

class Employee:
    def __init__(self, emp_id, name, salary):
        self.__emp_id = emp_id      # 私有:员工编号
        self.__name = name          # 私有:姓名
        self.__salary = salary      # 私有:薪资
        self.__performance_bonus = 0  # 私有:绩效奖金
    
    # getter 方法
    def get_emp_id(self):
        return self.__emp_id
    
    def get_name(self):
        return self.__name
    
    def get_salary(self):
        return self.__salary
    
    # setter 方法(带验证)
    def set_salary(self, salary):
        if salary < 0:
            raise ValueError("薪资不能为负数")
        self.__salary = salary
    
    def set_performance_bonus(self, bonus):
        """设置绩效奖金"""
        if bonus < 0:
            raise ValueError("奖金不能为负数")
        self.__performance_bonus = bonus
    
    def get_total_income(self):
        """计算总收入(薪资 + 奖金)"""
        return self.__salary + self.__performance_bonus
    
    def display_info(self):
        """显示员工信息"""
        print(f"工号:{self.__emp_id}")
        print(f"姓名:{self.__name}")
        print(f"底薪:{self.__salary}")
        print(f"绩效奖金:{self.__performance_bonus}")
        print(f"总收入:{self.get_total_income()}")
        print("-" * 30)

# 创建员工
emp1 = Employee("E001", "张三", 8000)
emp2 = Employee("E002", "李四", 9000)

emp1.set_performance_bonus(2000)
emp2.set_performance_bonus(1500)

emp1.display_info()
emp2.display_info()

八、继承

8.1 单继承

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self):
        print(f"{self.name} 正在吃东西")
    
    def sleep(self):
        print(f"{self.name} 正在睡觉")

class Dog(Animal):
    def bark(self):
        print(f"{self.name} 汪汪叫")
    
    def eat(self):  # 重写方法
        print(f"{self.name} 正在吃狗粮")
    
    def fetch(self):
        print(f"{self.name} 正在玩接球游戏")

class Cat(Animal):
    def meow(self):
        print(f"{self.name} 喵喵叫")
    
    def climb(self):
        print(f"{self.name} 正在爬树")

# 测试
dog = Dog("旺财", 3)
cat = Cat("咪咪", 2)

dog.eat()    # 旺财 正在吃狗粮(调用了重写的方法)
dog.sleep()  # 旺财 正在睡觉(继承自父类)
dog.bark()   # 旺财 汪汪叫
dog.fetch()  # 旺财 正在玩接球游戏

cat.eat()    # 咪咪 正在吃东西(使用父类方法)
cat.meow()   # 咪咪 喵喵叫
cat.climb()  # 咪咪 正在爬树

8.2 多继承

class Flyable:
    def fly(self):
        print("正在飞行")
    
    def takeoff(self):
        print("正在起飞")

class Swimmable:
    def swim(self):
        print("正在游泳")
    
    def dive(self):
        print("正在潜水")

class Duck(Flyable, Swimmable):
    def __init__(self, name):
        self.name = name
    
    def quack(self):
        print(f"{self.name} 嘎嘎叫")

# 鸭子会飞会游泳
duck = Duck("唐老鸭")
duck.takeoff()  # 正在起飞(继承自Flyable)
duck.fly()      # 正在飞行
duck.dive()     # 正在潜水(继承自Swimmable)
duck.swim()     # 正在游泳
duck.quack()    # 唐老鸭 嘎嘎叫

8.3 方法解析顺序(MRO)

class A:
    def method(self):
        print("A的方法")

class B(A):
    def method(self):
        print("B的方法")

class C(A):
    def method(self):
        print("C的方法")

class D(B, C):
    pass

# 查看方法解析顺序
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()
d.method()  # B的方法(按MRO顺序查找,先找到B)

8.4 super() 函数

class Vehicle:
    def __init__(self, brand, model):
        print("Vehicle __init__ 被调用")
        self.brand = brand
        self.model = model
    
    def start(self):
        print(f"{self.brand} {self.model} 启动")

class Car(Vehicle):
    def __init__(self, brand, model, doors):
        print("Car __init__ 被调用")
        super().__init__(brand, model)  # 调用父类构造方法
        self.doors = doors
    
    def start(self):
        super().start()  # 调用父类方法
        print(f"系好安全带,准备出发")

class ElectricCar(Car):
    def __init__(self, brand, model, doors, battery_capacity):
        print("ElectricCar __init__ 被调用")
        super().__init__(brand, model, doors)
        self.battery_capacity = battery_capacity
    
    def start(self):
        super().start()
        print(f"电池剩余:{self.battery_capacity}%,静音启动")

# 测试
tesla = ElectricCar("特斯拉", "Model 3", 4, 85)
tesla.start()

九、多态

9.1 多态的基本概念

class Animal:
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "汪汪汪"

class Cat(Animal):
    def make_sound(self):
        return "喵喵喵"

class Cow(Animal):
    def make_sound(self):
        return "哞哞哞"

def animal_sound(animal):
    """多态函数:可以接收任何Animal的子类"""
    print(animal.make_sound())

# 多态的体现
animals = [Dog(), Cat(), Cow()]
for animal in animals:
    animal_sound(animal)
# 汪汪汪
# 喵喵喵
# 哞哞哞

9.2 鸭子类型(Python特有)

class Duck:
    def quack(self):
        print("鸭子嘎嘎叫")

class Person:
    def quack(self):
        print("人在学鸭子叫")

class Robot:
    def quack(self):
        print("机器人发出嘎嘎声")

def make_quack(obj):
    """只要有quack方法就可以调用(鸭子类型)"""
    obj.quack()

# 不同类的对象,只要有相同的方法,就可以统一调用
make_quack(Duck())    # 鸭子嘎嘎叫
make_quack(Person())  # 人在学鸭子叫
make_quack(Robot())   # 机器人发出嘎嘎声

9.3 案例5:图形面积计算(多态实践)

from abc import ABC, abstractmethod
import math

class Shape(ABC):
    """抽象基类"""
    
    @abstractmethod
    def area(self):
        """计算面积(抽象方法)"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """计算周长(抽象方法)"""
        pass
    
    def describe(self):
        """普通方法"""
        return f"这是一个{self.__class__.__name__},面积:{self.area():.2f},周长:{self.perimeter():.2f}"

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return math.pi * self.radius ** 2
    
    def perimeter(self):
        return 2 * math.pi * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

class Triangle(Shape):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
    
    def area(self):
        """海伦公式"""
        s = (self.a + self.b + self.c) / 2
        return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))
    
    def perimeter(self):
        return self.a + self.b + self.c

# 多态演示
shapes = [
    Circle(5),
    Rectangle(4, 6),
    Triangle(3, 4, 5)
]

for shape in shapes:
    print(shape.describe())
# 这是一个Circle,面积:78.54,周长:31.42
# 这是一个Rectangle,面积:24.00,周长:20.00
# 这是一个Triangle,面积:6.00,周长:12.00

十、综合实战项目

项目1:动物园管理系统

class Animal:
    """动物基类"""
    total_animals = 0
    
    def __init__(self, name, age, species):
        self.name = name
        self.age = age
        self.species = species
        self.__health = 100  # 私有属性:健康值
        Animal.total_animals += 1
    
    def eat(self):
        print(f"{self.name} 正在吃东西")
        self.__health += 5
    
    def make_sound(self):
        pass
    
    def get_health(self):
        return self.__health
    
    def set_health(self, value):
        if 0 <= value <= 100:
            self.__health = value
        else:
            print("健康值无效")
    
    def info(self):
        return f"名称:{self.name},年龄:{self.age},物种:{self.species},健康值:{self.__health}"

class Lion(Animal):
    def __init__(self, name, age):
        super().__init__(name, age, "狮子")
    
    def make_sound(self):
        print(f"{self.name} 发出 roar 的吼叫声!")
    
    def hunt(self):
        print(f"{self.name} 正在捕猎")
        self.set_health(self.get_health() - 10)

class Elephant(Animal):
    def __init__(self, name, age):
        super().__init__(name, age, "大象")
    
    def make_sound(self):
        print(f"{self.name} 发出 trumpet 的声音!")
    
    def spray_water(self):
        print(f"{self.name} 正在喷水玩耍")
        self.set_health(self.get_health() + 10)

class Monkey(Animal):
    def __init__(self, name, age):
        super().__init__(name, age, "猴子")
    
    def make_sound(self):
        print(f"{self.name} 发出 chatter 的声音!")
    
    def climb(self):
        print(f"{self.name} 正在爬树")
        self.set_health(self.get_health() - 5)

class Zoo:
    def __init__(self, name):
        self.name = name
        self.animals = []
    
    def add_animal(self, animal):
        self.animals.append(animal)
        print(f"{animal.name} 已加入 {self.name}")
    
    def show_all_animals(self):
        print(f"\n{'='*40}")
        print(f"{self.name} 的动物列表")
        print(f"{'='*40}")
        for animal in self.animals:
            print(animal.info())
            animal.make_sound()
            print("-" * 30)
    
    def feed_all(self):
        print(f"\n正在给所有动物喂食...")
        for animal in self.animals:
            animal.eat()
    
    def get_zoo_stats(self):
        print(f"\n动物园统计:")
        print(f"动物园名称:{self.name}")
        print(f"动物总数:{len(self.animals)}")
        print(f"总动物种类(历史):{Animal.total_animals}")
        
        health_avg = sum(a.get_health() for a in self.animals) / len(self.animals)
        print(f"平均健康值:{health_avg:.1f}")

# 测试动物园系统
if __name__ == "__main__":
    # 创建动物园
    zoo = Zoo("野生动物园")
    
    # 添加动物
    lion = Lion("辛巴", 5)
    elephant = Elephant("多多", 8)
    monkey = Monkey("悟空", 3)
    
    zoo.add_animal(lion)
    zoo.add_animal(elephant)
    zoo.add_animal(monkey)
    
    # 展示所有动物
    zoo.show_all_animals()
    
    # 喂食
    zoo.feed_all()
    
    # 展示统计
    zoo.get_zoo_stats()
    
    # 特殊行为
    print(f"\n特殊行为演示:")
    lion.hunt()
    elephant.spray_water()
    monkey.climb()
    
    # 最终状态
    zoo.show_all_animals()

项目2:猫狗大战游戏

import random
import time

class Pet:
    """宠物基类"""
    def __init__(self, name, health, attack_power):
        self.name = name
        self.max_health = health
        self.health = health
        self.attack_power = attack_power
        self.is_alive = True
    
    def attack(self, target):
        """攻击目标"""
        damage = random.randint(self.attack_power - 5, self.attack_power + 5)
        damage = max(1, damage)  # 至少造成1点伤害
        target.take_damage(damage)
        print(f"{self.name} 攻击了 {target.name},造成 {damage} 点伤害!")
        time.sleep(0.5)
    
    def take_damage(self, damage):
        """受到伤害"""
        self.health -= damage
        if self.health <= 0:
            self.health = 0
            self.is_alive = False
            print(f"{self.name} 倒下了!")
    
    def heal(self, amount):
        """治疗"""
        self.health = min(self.max_health, self.health + amount)
        print(f"{self.name} 恢复了 {amount} 生命值,当前生命:{self.health}")
    
    def show_status(self):
        """显示状态"""
        bar_length = 20
        health_bar = "█" * int(self.health / self.max_health * bar_length)
        health_bar += "░" * (bar_length - len(health_bar))
        print(f"{self.name}: [{health_bar}] {self.health}/{self.max_health}")
    
    def __str__(self):
        return f"{self.name}({self.health}/{self.max_health})"

class Dog(Pet):
    def __init__(self, name):
        super().__init__(name, health=120, attack_power=25)
        self.species = "狗"
    
    def special_skill(self, target):
        """狗的技能:撕咬(造成额外伤害)"""
        print(f"{self.name} 使用技能:疯狂撕咬!")
        extra_damage = random.randint(15, 30)
        target.take_damage(extra_damage)
        print(f"额外造成 {extra_damage} 点伤害!")
        time.sleep(0.5)

class Cat(Pet):
    def __init__(self, name):
        super().__init__(name, health=100, attack_power=30)
        self.species = "猫"
    
    def special_skill(self, target):
        """猫的技能:闪避反击(造成伤害并回血)"""
        print(f"{self.name} 使用技能:闪避反击!")
        # 闪避后反击
        heal_amount = random.randint(10, 20)
        self.heal(heal_amount)
        
        counter_damage = random.randint(20, 35)
        target.take_damage(counter_damage)
        print(f"反击造成 {counter_damage} 点伤害!")
        time.sleep(0.5)

class Game:
    def __init__(self, player1, player2):
        self.player1 = player1
        self.player2 = player2
        self.round = 0
    
    def display_battle_info(self):
        print("\n" + "="*50)
        print(f"第 {self.round} 回合")
        print("="*50)
        self.player1.show_status()
        self.player2.show_status()
        print("-"*50)
    
    def player_turn(self, attacker, defender):
        """玩家回合"""
        print(f"\n{attacker.name} 的回合!")
        print("1. 普通攻击")
        print("2. 使用技能")
        print("3. 治疗")
        
        choice = input("请选择行动:")
        
        if choice == "1":
            attacker.attack(defender)
        elif choice == "2":
            if random.random() < 0.8:  # 80%成功率
                attacker.special_skill(defender)
            else:
                print(f"{attacker.name} 技能使用失败!")
        elif choice == "3":
            heal_amount = random.randint(15, 30)
            attacker.heal(heal_amount)
        else:
            print("无效选择,进行普通攻击")
            attacker.attack(defender)
    
    def computer_turn(self, attacker, defender):
        """电脑回合"""
        print(f"\n{attacker.name} 的回合!")
        time.sleep(1)
        
        action = random.choice(["attack", "skill", "heal"])
        
        if action == "attack":
            attacker.attack(defender)
        elif action == "skill":
            if random.random() < 0.7:  # 70%成功率
                attacker.special_skill(defender)
            else:
                print(f"{attacker.name} 技能使用失败!")
                attacker.attack(defender)
        else:
            heal_amount = random.randint(15, 30)
            attacker.heal(heal_amount)
    
    def play_round(self):
        """执行一回合"""
        self.round += 1
        self.display_battle_info()
        
        # 根据速度决定谁先攻击(这里简单用随机)
        if random.random() < 0.5:
            self.player_turn(self.player1, self.player2)
            if self.player2.is_alive:
                self.computer_turn(self.player2, self.player1)
        else:
            self.computer_turn(self.player2, self.player1)
            if self.player1.is_alive:
                self.player_turn(self.player1, self.player2)
    
    def start(self):
        """开始游戏"""
        print("\n" + "="*50)
        print("🐱🐶 猫狗大战游戏开始! 🐱🐶")
        print("="*50)
        
        while self.player1.is_alive and self.player2.is_alive:
            self.play_round()
            time.sleep(1)
        
        # 游戏结束
        print("\n" + "="*50)
        print("游戏结束!")
        if self.player1.is_alive:
            print(f"🎉 {self.player1.name} 获胜! 🎉")
        else:
            print(f"🎉 {self.player2.name} 获胜! 🎉")
        print("="*50)

# 启动游戏
if __name__ == "__main__":
    print("选择游戏模式:")
    print("1. 单人模式(玩家 vs 电脑)")
    print("2. 双人模式(玩家1 vs 玩家2)")
    
    mode = input("请选择模式:")
    
    if mode == "1":
        # 单人模式
        dog = Dog("旺财")
        cat = Cat("咪咪")
        print("请选择你的角色:")
        print("1. 狗(高生命值)")
        print("2. 猫(高攻击力)")
        choice = input("请选择:")
        
        if choice == "1":
            player = dog
            computer = cat
        else:
            player = cat
            computer = dog
        
        print(f"\n你选择了 {player.name}{player.species})")
        print(f"电脑选择了 {computer.name}{computer.species})")
        
        game = Game(player, computer)
        game.start()
    
    elif mode == "2":
        # 双人模式
        dog = Dog("旺财")
        cat = Cat("咪咪")
        
        print("\n玩家1选择:")
        print("1. 狗")
        print("2. 猫")
        choice1 = input("请选择:")
        player1 = dog if choice1 == "1" else cat
        
        print("\n玩家2获得另一个角色")
        player2 = cat if choice1 == "1" else dog
        
        print(f"\n玩家1:{player1.name}{player1.species})")
        print(f"玩家2:{player2.name}{player2.species})")
        
        game = Game(player1, player2)
        game.start()

十一、常见面试题与总结

面试题精选

Q1:Python中类变量和实例变量的区别?

A:类变量所有实例共享,通过类名修改会影响所有实例;实例变量每个实例独立。类变量在方法外定义,实例变量在 __init__ 中以 self. 定义。

Q2:self 是什么?可以不写吗?

A:self 代表实例本身,是实例方法的第一个参数。Python 要求必须写,但可以改成其他名字(不推荐)。

Q3:私有属性真的私有吗?

A:不是真正的私有,Python 只是进行了名称修饰(name mangling),变成 _类名__属性,外部仍然可以访问。

Q4:super() 的作用是什么?

A:用于调用父类的方法,特别是在多继承和方法重写时非常有用,可以避免直接使用父类名。

Q5:Python 支持方法重载吗?

A:不支持传统的方法重载(同名不同参数)。但可以通过默认参数、*args**kwargs 实现类似效果。

项目小结

通过本文的学习,你应该掌握了:

知识点 核心内容
类与对象 类是模板,对象是实例
构造方法 __init__ 初始化对象
析构方法 __del__ 释放资源
self 参数 代表实例本身
类变量 所有实例共享
实例变量 每个实例独立
类方法 @classmethod,可访问类变量
静态方法 @staticmethod,工具函数
封装 私有成员 __ + getter/setter
继承 单继承、多继承、MRO
方法重写 子类覆盖父类方法
多态 同一接口,不同实现

写在最后

面向对象编程是 Python 的核心特性之一,掌握它不仅能让你写出更优雅的代码,还能为后续学习设计模式、框架开发打下坚实基础。

建议学习路径:

  1. 先理解类和对象的概念
  2. 多写小案例练习(如银行账户、学生管理系统)
  3. 尝试用面向对象重构之前的面向过程代码
  4. 阅读优秀的 Python 开源项目源码

如果你觉得本文对你有帮助,欢迎点赞、收藏、转发支持我继续创作!
更多Python详细学习路径,私信回复“Python”即可领取

更多推荐