第四单元:面向对象编程

掌握类与对象、继承、多态等面向对象编程核心概念

预计学习时间:5-6小时

单元介绍

欢迎来到Python基础课程的第四单元!在这个单元中,你将学习面向对象编程(OOP)的核心概念,这是现代编程的重要范式。

学习目标

  • 理解类和对象的概念
  • 掌握类的定义和对象的创建
  • 理解继承的原理和应用
  • 掌握多态的概念和使用
  • 理解封装的思想
  • 学习Python的特殊方法
  • 能够设计和实现面向对象的程序

学习提示

💡 重要提示:面向对象编程是一种思维方式,需要通过实践来理解。建议你多动手编写代码,尝试设计和实现不同的类,加深对OOP概念的理解!

4.1 类与对象:OOP的基本概念

在面向对象编程中,类是对象的蓝图或模板,对象是类的实例。

定义类

在Python中,使用class关键字来定义类:

# 定义一个简单的类
class Person:
    """人员类"""
    
    # 类属性
    species = "人类"
    
    # 初始化方法
    def __init__(self, name, age):
        """初始化方法"""
        # 实例属性
        self.name = name
        self.age = age
    
    # 实例方法
    def greet(self):
        """问候方法"""
        return f"你好,我叫{self.name},今年{self.age}岁。"
    
    # 实例方法
    def celebrate_birthday(self):
        """庆祝生日"""
        self.age += 1
        return f"生日快乐!{self.name}现在{self.age}岁了。"

# 创建对象
person1 = Person("张三", 30)
person2 = Person("李四", 25)

# 访问实例属性
print(f"person1的姓名: {person1.name}")
print(f"person1的年龄: {person1.age}")

# 调用实例方法
print(person1.greet())
print(person1.celebrate_birthday())

# 访问类属性
print(f"person1的物种: {person1.species}")
print(f"Person类的物种: {Person.species}")

类的属性和方法

类可以有类属性和实例属性,以及实例方法和类方法:

class Car:
    """汽车类"""
    
    # 类属性
    wheels = 4
    
    def __init__(self, brand, model, year):
        """初始化方法"""
        self.brand = brand  # 实例属性
        self.model = model  # 实例属性
        self.year = year    # 实例属性
        self.mileage = 0    # 实例属性
    
    # 实例方法
    def drive(self, distance):
        """驾驶方法"""
        self.mileage += distance
        return f"{self.brand} {self.model} 行驶了{distance}公里,总里程{self.mileage}公里。"
    
    # 实例方法
    def get_info(self):
        """获取信息"""
        return f"{self.year} {self.brand} {self.model},里程{self.mileage}公里"
    
    # 类方法
    @classmethod
    def from_string(cls, car_string):
        """从字符串创建汽车对象"""
        brand, model, year = car_string.split(",")
        return cls(brand, model, int(year))
    
    # 静态方法
    @staticmethod
    def is_valid_year(year):
        """检查年份是否有效"""
        return 1900 <= year <= 2026

# 创建对象
car1 = Car("丰田", "卡罗拉", 2020)
print(car1.drive(100))
print(car1.get_info())

# 使用类方法创建对象
car2 = Car.from_string("本田,思域,2021")
print(car2.get_info())

# 使用静态方法
print(f"2020年是否有效: {Car.is_valid_year(2020)}")
print(f"1899年是否有效: {Car.is_valid_year(1899)}")

# 访问类属性
print(f"汽车有{Car.wheels}个轮子")

4.2 继承:代码复用的利器

继承是面向对象编程的重要特性,它允许一个类继承另一个类的属性和方法。

基本继承

创建一个子类来继承父类的属性和方法:

# 父类
class Animal:
    """动物类"""
    
    def __init__(self, name):
        """初始化方法"""
        self.name = name
    
    def eat(self):
        """吃方法"""
        return f"{self.name}在吃东西。"
    
    def sleep(self):
        """睡觉方法"""
        return f"{self.name}在睡觉。"

# 子类
class Dog(Animal):
    """狗类"""
    
    def __init__(self, name, breed):
        """初始化方法"""
        # 调用父类的初始化方法
        super().__init__(name)
        self.breed = breed
    
    # 重写父类方法
    def eat(self):
        """吃方法"""
        return f"{self.name}({self.breed})在啃骨头。"
    
    # 新增方法
    def bark(self):
        """ bark方法"""
        return f"{self.name}在汪汪叫!"

# 另一个子类
class Cat(Animal):
    """猫类"""
    
    def __init__(self, name, color):
        """初始化方法"""
        super().__init__(name)
        self.color = color
    
    # 重写父类方法
    def eat(self):
        """吃方法"""
        return f"{self.name}({self.color}色)在吃鱼。"
    
    # 新增方法
    def meow(self):
        """ meow方法"""
        return f"{self.name}在喵喵叫!"

# 创建对象
dog = Dog("旺财", "金毛")
cat = Cat("咪咪", "黑白")

# 调用方法
print(dog.eat())
print(dog.sleep())
print(dog.bark())

print(cat.eat())
print(cat.sleep())
print(cat.meow())

# 检查继承关系
print(f"Dog是Animal的子类: {issubclass(Dog, Animal)}")
print(f"Cat是Animal的子类: {issubclass(Cat, Animal)}")
print(f"dog是Dog的实例: {isinstance(dog, Dog)}")
print(f"dog是Animal的实例: {isinstance(dog, Animal)}")

多重继承

Python支持多重继承,一个类可以继承多个父类:

# 第一个父类
class Flyable:
    """可飞行的"""
    
    def fly(self):
        """飞行方法"""
        return "正在飞行"

# 第二个父类
class Swimmable:
    """可游泳的"""
    
    def swim(self):
        """游泳方法"""
        return "正在游泳"

# 子类,继承多个父类
class Duck(Flyable, Swimmable):
    """鸭子类"""
    
    def __init__(self, name):
        """初始化方法"""
        self.name = name
    
    def quack(self):
        """嘎嘎叫方法"""
        return f"{self.name}在嘎嘎叫"

# 创建对象
duck = Duck("唐老鸭")

# 调用方法
print(duck.quack())
print(duck.fly())
print(duck.swim())

# 检查继承关系
print(f"Duck是Flyable的子类: {issubclass(Duck, Flyable)}")
print(f"Duck是Swimmable的子类: {issubclass(Duck, Swimmable)}")

4.3 多态:同一种行为的不同表现

多态是指不同类的对象对同一方法调用做出不同的响应。

多态的实现

通过方法重写实现多态:

class Shape:
    """形状类"""
    
    def area(self):
        """计算面积"""
        pass

class Rectangle(Shape):
    """矩形类"""
    
    def __init__(self, length, width):
        """初始化方法"""
        self.length = length
        self.width = width
    
    def area(self):
        """计算面积"""
        return self.length * self.width

class Circle(Shape):
    """圆形类"""
    
    def __init__(self, radius):
        """初始化方法"""
        self.radius = radius
    
    def area(self):
        """计算面积"""
        import math
        return math.pi * self.radius ** 2

class Triangle(Shape):
    """三角形类"""
    
    def __init__(self, base, height):
        """初始化方法"""
        self.base = base
        self.height = height
    
    def area(self):
        """计算面积"""
        return 0.5 * self.base * self.height

# 创建不同形状的对象
shapes = [
    Rectangle(5, 3),
    Circle(4),
    Triangle(6, 4)
]

# 多态:调用同一方法,不同对象有不同的实现
for shape in shapes:
    print(f"{shape.__class__.__name__}的面积: {shape.area()}")

# 函数使用多态
def print_area(shape):
    """打印形状的面积"""
    print(f"面积: {shape.area()}")

# 传入不同类型的对象
print_area(Rectangle(10, 2))
print_area(Circle(5))
print_area(Triangle(3, 6))

4.4 封装:保护数据的安全

封装是指将数据和操作数据的方法包装在一起,对外部隐藏实现细节。

私有属性和方法

在Python中,使用双下划线前缀来定义私有属性和方法:

class BankAccount:
    """银行账户类"""
    
    def __init__(self, account_number, balance):
        """初始化方法"""
        self.account_number = account_number  # 公共属性
        self.__balance = balance  # 私有属性
    
    # 公共方法
    def deposit(self, amount):
        """存款"""
        if amount > 0:
            self.__balance += amount
            return f"存款成功,余额: {self.__balance}"
        else:
            return "存款金额必须大于0"
    
    # 公共方法
    def withdraw(self, amount):
        """取款"""
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return f"取款成功,余额: {self.__balance}"
        else:
            return "取款金额无效"
    
    # 公共方法
    def get_balance(self):
        """获取余额"""
        return self.__balance
    
    # 私有方法
    def __validate_amount(self, amount):
        """验证金额"""
        return isinstance(amount, (int, float)) and amount > 0

# 创建账户对象
account = BankAccount("123456789", 1000)

# 访问公共属性
print(f"账号: {account.account_number}")

# 调用公共方法
print(account.deposit(500))
print(account.withdraw(200))
print(f"余额: {account.get_balance()}")

# 尝试访问私有属性(会失败)
# print(account.__balance)  # 会引发AttributeError

# 尝试调用私有方法(会失败)
# account.__validate_amount(100)  # 会引发AttributeError

# 注意:Python的私有属性和方法只是名称修饰,并非真正的私有
# 可以通过 _类名__属性名 访问
print(f"通过名称修饰访问余额: {account._BankAccount__balance}")

属性装饰器

使用@property装饰器创建属性的getter和setter:

class Person:
    """人员类"""
    
    def __init__(self, name, age):
        """初始化方法"""
        self._name = name  # 受保护的属性
        self._age = age    # 受保护的属性
    
    # getter方法
    @property
    def name(self):
        """获取姓名"""
        return self._name
    
    # setter方法
    @name.setter
    def name(self, value):
        """设置姓名"""
        if isinstance(value, str) and value.strip():
            self._name = value
        else:
            raise ValueError("姓名必须是非空字符串")
    
    # getter方法
    @property
    def age(self):
        """获取年龄"""
        return self._age
    
    # setter方法
    @age.setter
    def age(self, value):
        """设置年龄"""
        if isinstance(value, int) and 0 <= value <= 150:
            self._age = value
        else:
            raise ValueError("年龄必须是0-150之间的整数")

# 创建对象
person = Person("张三", 30)

# 使用属性
print(f"姓名: {person.name}")
print(f"年龄: {person.age}")

# 修改属性
person.name = "李四"
person.age = 25
print(f"修改后 - 姓名: {person.name}")
print(f"修改后 - 年龄: {person.age}")

# 尝试设置无效值
# person.name = ""  # 会引发ValueError
# person.age = 200  # 会引发ValueError

4.5 特殊方法:Python的魔法方法

Python提供了许多特殊方法,也称为魔法方法,它们以双下划线开头和结尾。

常用特殊方法

class Vector:
    """向量类"""
    
    def __init__(self, x, y):
        """初始化方法"""
        self.x = x
        self.y = y
    
    # 字符串表示
    def __str__(self):
        """返回字符串表示"""
        return f"Vector({self.x}, {self.y})"
    
    # 官方字符串表示
    def __repr__(self):
        """返回官方字符串表示"""
        return f"Vector({self.x}, {self.y})"
    
    # 加法
    def __add__(self, other):
        """加法运算"""
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        return NotImplemented
    
    # 减法
    def __sub__(self, other):
        """减法运算"""
        if isinstance(other, Vector):
            return Vector(self.x - other.x, self.y - other.y)
        return NotImplemented
    
    # 乘法
    def __mul__(self, scalar):
        """乘法运算"""
        if isinstance(scalar, (int, float)):
            return Vector(self.x * scalar, self.y * scalar)
        return NotImplemented
    
    # 长度
    def __abs__(self):
        """绝对值"""
        import math
        return math.sqrt(self.x ** 2 + self.y ** 2)
    
    # 相等性比较
    def __eq__(self, other):
        """相等性比较"""
        if isinstance(other, Vector):
            return self.x == other.x and self.y == other.y
        return False
    
    # 小于比较
    def __lt__(self, other):
        """小于比较"""
        if isinstance(other, Vector):
            return abs(self) < abs(other)
        return NotImplemented

# 创建向量对象
v1 = Vector(3, 4)
v2 = Vector(1, 2)

# 使用特殊方法
print(f"v1: {v1}")
print(f"v2: {v2}")
print(f"v1 + v2: {v1 + v2}")
print(f"v1 - v2: {v1 - v2}")
print(f"v1 * 2: {v1 * 2}")
print(f"|v1|: {abs(v1)}")
print(f"v1 == v2: {v1 == v2}")
print(f"v1 < v2: {v1 < v2}")
print(f"v2 < v1: {v2 < v1}")

容器特殊方法

class MyList:
    """自定义列表类"""
    
    def __init__(self, *items):
        """初始化方法"""
        self.items = list(items)
    
    # 长度
    def __len__(self):
        """返回长度"""
        return len(self.items)
    
    # 索引访问
    def __getitem__(self, index):
        """获取索引元素"""
        return self.items[index]
    
    # 索引赋值
    def __setitem__(self, index, value):
        """设置索引元素"""
        self.items[index] = value
    
    # 迭代
    def __iter__(self):
        """返回迭代器"""
        return iter(self.items)
    
    # 包含
    def __contains__(self, item):
        """检查是否包含元素"""
        return item in self.items
    
    # 字符串表示
    def __str__(self):
        """返回字符串表示"""
        return str(self.items)

# 创建自定义列表
my_list = MyList(1, 2, 3, 4, 5)

# 使用特殊方法
print(f"列表: {my_list}")
print(f"长度: {len(my_list)}")
print(f"索引2: {my_list[2]}")

# 修改元素
my_list[0] = 10
print(f"修改后: {my_list}")

# 迭代
print("迭代列表:")
for item in my_list:
    print(item)

# 包含
print(f"3在列表中: {3 in my_list}")
print(f"10在列表中: {10 in my_list}")

4.6 单元练习题

太棒了!你已经学完了第四单元的所有内容。现在让我们通过一些练习来巩固所学知识吧!

练习题1:类的基本使用

创建一个Student类,包含姓名、年龄、学号和成绩属性,以及计算平均成绩的方法。

查看参考答案
class Student:
    """学生类"""
    
    def __init__(self, name, age, student_id):
        """初始化方法"""
        self.name = name
        self.age = age
        self.student_id = student_id
        self.grades = []
    
    def add_grade(self, grade):
        """添加成绩"""
        if 0 <= grade <= 100:
            self.grades.append(grade)
            return f"成绩{grade}添加成功"
        else:
            return "成绩必须在0-100之间"
    
    def average_grade(self):
        """计算平均成绩"""
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)
    
    def __str__(self):
        """返回字符串表示"""
        return f"学生: {self.name}, 年龄: {self.age}, 学号: {self.student_id}, 平均成绩: {self.average_grade():.2f}"

# 测试
student = Student("张三", 18, "2026001")
print(student.add_grade(90))
print(student.add_grade(85))
print(student.add_grade(95))
print(student)
print(f"平均成绩: {student.average_grade():.2f}")

练习题2:继承

创建一个Employee基类,然后创建ManagerDeveloper子类,每个子类有自己的特殊方法。

查看参考答案
class Employee:
    """员工类"""
    
    def __init__(self, name, id, salary):
        """初始化方法"""
        self.name = name
        self.id = id
        self.salary = salary
    
    def get_info(self):
        """获取信息"""
        return f"姓名: {self.name}, 工号: {self.id},  salary: {self.salary}"
    
    def work(self):
        """工作方法"""
        return f"{self.name}在工作"

class Manager(Employee):
    """经理类"""
    
    def __init__(self, name, id, salary, department):
        """初始化方法"""
        super().__init__(name, id, salary)
        self.department = department
    
    def work(self):
        """工作方法"""
        return f"{self.name}在管理{self.department}部门"
    
    def manage(self):
        """管理方法"""
        return f"{self.name}在管理员工"

class Developer(Employee):
    """开发人员类"""
    
    def __init__(self, name, id, salary, programming_language):
        """初始化方法"""
        super().__init__(name, id, salary)
        self.programming_language = programming_language
    
    def work(self):
        """工作方法"""
        return f"{self.name}在用{self.programming_language}编程"
    
    def code(self):
        """编程方法"""
        return f"{self.name}在编写代码"

# 测试
manager = Manager("王五", "M001", 15000, "技术部")
developer = Developer("赵六", "D001", 10000, "Python")

print(manager.get_info())
print(manager.work())
print(manager.manage())

print(developer.get_info())
print(developer.work())
print(developer.code())

练习题3:多态

创建一个Vehicle基类,然后创建不同的交通工具子类,实现多态。

查看参考答案
class Vehicle:
    """交通工具类"""
    
    def __init__(self, brand, model):
        """初始化方法"""
        self.brand = brand
        self.model = model
    
    def start(self):
        """启动方法"""
        pass
    
    def stop(self):
        """停止方法"""
        pass

class Car(Vehicle):
    """汽车类"""
    
    def start(self):
        """启动方法"""
        return f"{self.brand} {self.model} 启动了发动机"
    
    def stop(self):
        """停止方法"""
        return f"{self.brand} {self.model} 熄火了"

class Bicycle(Vehicle):
    """自行车类"""
    
    def start(self):
        """启动方法"""
        return f"{self.brand} {self.model} 开始骑行"
    
    def stop(self):
        """停止方法"""
        return f"{self.brand} {self.model} 停止骑行"

class Boat(Vehicle):
    """船类"""
    
    def start(self):
        """启动方法"""
        return f"{self.brand} {self.model} 启航"
    
    def stop(self):
        """停止方法"""
        return f"{self.brand} {self.model} 停靠"

# 多态
vehicles = [
    Car("丰田", "卡罗拉"),
    Bicycle("捷安特", "ATX770"),
    Boat("雅马哈", "快艇")
]

for vehicle in vehicles:
    print(vehicle.start())
    print(vehicle.stop())
    print()

练习题4:封装

创建一个Person类,使用私有属性和属性装饰器来保护数据。

查看参考答案
class Person:
    """人员类"""
    
    def __init__(self, name, age, email):
        """初始化方法"""
        self._name = name
        self._age = age
        self._email = email
    
    @property
    def name(self):
        """获取姓名"""
        return self._name
    
    @name.setter
    def name(self, value):
        """设置姓名"""
        if isinstance(value, str) and value.strip():
            self._name = value
        else:
            raise ValueError("姓名必须是非空字符串")
    
    @property
    def age(self):
        """获取年龄"""
        return self._age
    
    @age.setter
    def age(self, value):
        """设置年龄"""
        if isinstance(value, int) and 0 <= value <= 150:
            self._age = value
        else:
            raise ValueError("年龄必须是0-150之间的整数")
    
    @property
    def email(self):
        """获取邮箱"""
        return self._email
    
    @email.setter
    def email(self, value):
        """设置邮箱"""
        if isinstance(value, str) and '@' in value:
            self._email = value
        else:
            raise ValueError("邮箱格式不正确")
    
    def __str__(self):
        """返回字符串表示"""
        return f"姓名: {self.name}, 年龄: {self.age}, 邮箱: {self.email}"

# 测试
person = Person("张三", 30, "zhangsan@example.com")
print(person)

# 修改属性
person.name = "李四"
person.age = 25
person.email = "lisi@example.com"
print(person)

# 尝试设置无效值
# person.age = 200  # 会引发ValueError
# person.email = "invalid-email"  # 会引发ValueError

练习题5:特殊方法

创建一个ComplexNumber类,实现复数的基本运算。

查看参考答案
class ComplexNumber:
    """复数类"""
    
    def __init__(self, real, imag):
        """初始化方法"""
        self.real = real
        self.imag = imag
    
    def __str__(self):
        """返回字符串表示"""
        if self.imag >= 0:
            return f"{self.real} + {self.imag}i"
        else:
            return f"{self.real} - {abs(self.imag)}i"
    
    def __add__(self, other):
        """加法运算"""
        if isinstance(other, ComplexNumber):
            return ComplexNumber(self.real + other.real, self.imag + other.imag)
        return NotImplemented
    
    def __sub__(self, other):
        """减法运算"""
        if isinstance(other, ComplexNumber):
            return ComplexNumber(self.real - other.real, self.imag - other.imag)
        return NotImplemented
    
    def __mul__(self, other):
        """乘法运算"""
        if isinstance(other, ComplexNumber):
            real = self.real * other.real - self.imag * other.imag
            imag = self.real * other.imag + self.imag * other.real
            return ComplexNumber(real, imag)
        return NotImplemented
    
    def __eq__(self, other):
        """相等性比较"""
        if isinstance(other, ComplexNumber):
            return self.real == other.real and self.imag == other.imag
        return False

# 测试
c1 = ComplexNumber(3, 4)
c2 = ComplexNumber(1, 2)

print(f"c1: {c1}")
print(f"c2: {c2}")
print(f"c1 + c2: {c1 + c2}")
print(f"c1 - c2: {c1 - c2}")
print(f"c1 * c2: {c1 * c2}")
print(f"c1 == c2: {c1 == c2}")

c3 = ComplexNumber(3, 4)
print(f"c1 == c3: {c1 == c3}")

单元总结

🎉 恭喜你完成了第四单元的学习!

  • 你理解了类和对象的概念
  • 你掌握了类的定义和对象的创建
  • 你理解了继承的原理和应用
  • 你掌握了多态的概念和使用
  • 你理解了封装的思想
  • 你学习了Python的特殊方法
  • 你能够设计和实现面向对象的程序

继续加油,下一个单元我们将学习工程化实践!