04-面向对象编程

judgingly
4
2026-02-14

Python 学习教程 - 第四篇:面向对象编程

欢迎继续 Python 学习之旅!今天我们将学习 Python 最强大的特性之一:面向对象编程(OOP)。

目录

  1. 面向对象编程基础
  2. 类和对象
  3. 构造函数和初始化
  4. 属性和方法
  5. 封装
  6. 继承
  7. 多态
  8. 抽象类
  9. 实用练习](#实用练习)
  10. 总结

面向对象编程基础

什么是面向对象编程?

面向对象编程是一种编程范式,它将程序组织成"对象",每个对象包含数据和操作数据的方法。

面向对象 vs 面向过程

面向过程(过程式编程)

  • 关注"怎么做"
  • 函数和过程是主要构建块
  • 数据和操作数据的函数分离

面向对象(OOP)

  • 关注"谁来做"
  • 类和对象是主要构建块
  • 数据和操作数据的函数封装在一起

OOP 的三大特性

  1. 封装(Encapsulation):隐藏内部实现,只暴露必要接口
  2. 继承(Inheritance):代码复用,建立类之间的关系
  3. 多态(Polymorphism):同一接口,不同实现

类和对象

类的定义

类是对象的蓝图或模板。

# 定义一个简单的类
class Dog:
    """狗类"""

    # 类属性
    species = "哺乳动物"

    def __init__(self, name, age):
        """构造函数:创建对象时自动调用"""
        self.name = name  # 实例属性
        self.age = age    # 实例属性

    # 实例方法
    def bark(self):
        """狗叫的方法"""
        print(f"{self.name} 汪汪叫!")

    def introduce(self):
        """自我介绍"""
        print(f"我是 {self.name},{self.age} 岁,是 {self.species}")

# 创建对象(实例化)
dog1 = Dog("旺财", 3)
dog2 = Dog("小黄", 5)

# 调用方法
dog1.bark()        # 旺财 汪汪叫!
dog2.bark()        # 小黄 汪汪叫!

dog1.introduce()   # 我是 旺财,3 岁,是 哺乳动物
dog2.introduce()   # 我是 小黄,5 岁,是 哺乳动物

对象和类的关系

  • :抽象的概念,定义了对象的属性和方法
  • 对象:类的实例,具体的实体
  • 实例化:从类创建对象的过程

构造函数和初始化

__init__ 方法

__init__ 是构造函数,在创建对象时自动调用。

class Person:
    def __init__(self, name, age, gender):
        """初始化方法"""
        self.name = name
        self.age = age
        self.gender = gender

    def get_info(self):
        """获取信息"""
        return f"{self.name}, {self.age}岁, {self.gender}"

# 创建对象
p1 = Person("张三", 25, "男")
p2 = Person("李四", 30, "女")

print(p1.get_info())  # 张三, 25岁, 男
print(p2.get_info())  # 李四, 30岁, 女

默认参数

可以为构造函数提供默认参数。

class Person:
    def __init__(self, name, age=18, gender="未知"):
        self.name = name
        self.age = age
        self.gender = gender

# 使用默认参数
p1 = Person("张三")           # 使用默认值
p2 = Person("李四", 25)       # 只提供年龄
p3 = Person("王五", 30, "男") # 全部参数

print(p1.name, p1.age, p1.gender)  # 张三 18 未知
print(p2.name, p2.age, p2.gender)  # 李四 25 未知
print(p3.name, p3.age, p3.gender)  # 王五 30 男

自定义构造函数

可以重载 __new__ 方法来控制对象创建过程。

class Counter:
    _count = 0  # 类变量

    def __new__(cls):
        cls._count += 1
        return super().__new__(cls)

    def __init__(self):
        self.id = Counter._count

# 创建多个对象
c1 = Counter()
c2 = Counter()
c3 = Counter()

print(c1.id)  # 1
print(c2.id)  # 2
print(c3.id)  # 3
print(Counter._count)  # 3

属性和方法

实例属性 vs 类属性

实例属性:每个对象独有的属性

class Car:
    brand = "Toyota"  # 类属性(所有对象共享)

    def __init__(self, model, color):
        self.model = model  # 实例属性
        self.color = color  # 实例属性

car1 = Car("Camry", "红色")
car2 = Car("Corolla", "蓝色")

print(car1.brand)  # Toyota(类属性)
print(car1.model)  # Camry(实例属性)
print(car2.brand)  # Toyota(类属性)
print(car2.model)  # Corolla(实例属性)

实例方法 vs 类方法 vs 静态方法

class MathUtil:
    # 实例方法:需要 self 参数
    def add(self, a, b):
        return a + b

    # 类方法:需要 cls 参数,操作类属性
    @classmethod
    def multiply(cls, a, b):
        return a * b

    # 静态方法:不需要 self 或 cls
    @staticmethod
    def power(a, b):
        return a ** b

# 实例方法
mu = MathUtil()
print(mu.add(2, 3))          # 5

# 类方法
print(MathUtil.multiply(2, 3))  # 6

# 静态方法
print(MathUtil.power(2, 3))    # 8

Getter 和 Setter

使用 @property 装饰器创建属性访问器。

class Person:
    def __init__(self, name, age):
        self._name = name  # 私有属性(约定以 _ 开头)
        self._age = age

    # Getter
    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    # Setter
    @name.setter
    def name(self, new_name):
        if len(new_name) > 0:
            self._name = new_name
        else:
            print("名字不能为空!")

    @age.setter
    def age(self, new_age):
        if new_age >= 0:
            self._age = new_age
        else:
            print("年龄不能为负数!")

# 使用
p = Person("张三", 25)
print(p.name)  # 张三
print(p.age)   # 25

p.name = "李四"  # 通过 setter 修改
print(p.name)   # 李四

p.age = 30
print(p.age)    # 30

p.age = -5  # 不会修改,会打印错误信息
print(p.age)  # 30

封装

封装的概念

封装是指隐藏对象的内部实现细节,只暴露必要的接口。在 Python 中,通过命名约定和访问修饰符实现封装。

私有属性和方法

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
            print(f"存款 {amount} 元成功")
        else:
            print("存款金额必须大于0")

    def withdraw(self, amount):
        """取款"""
        if amount > 0 and amount <= self._balance:
            self._balance -= amount
            print(f"取款 {amount} 元成功")
        else:
            print("取款失败:金额无效或余额不足")

    def get_balance(self):
        """获取余额(公共接口)"""
        return self._balance

# 使用
account = BankAccount("123456789", 1000)
account.deposit(500)     # 存款 500 元成功
account.withdraw(200)    # 取款 200 元成功
print(account.get_balance())  # 1300
print(account._balance)       # 1300(可以直接访问,但不推荐)

__ 双下划线(名称修饰)

__ 开头的属性会被 Python 名称修饰(name mangling)。

class Example:
    def __init__(self):
        self.__private = "私有属性"

    def __private_method(self):
        print("这是一个私有方法")

    def public_method(self):
        print("这是一个公共方法")
        self.__private_method()  # 可以调用

# 使用
e = Example()
print(e.__private)  # 报错:AttributeError
e.__private_method()  # 报错:AttributeError
e.public_method()  # 可以调用

继承

继承的概念

继承允许创建一个新类,继承现有类的属性和方法。

基本继承

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self):
        print("动物发出声音")

    def eat(self):
        print("动物在吃东西")

# Dog 类继承 Animal 类
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用父类构造函数
        self.breed = breed

    def speak(self):
        print(f"{self.name} 汪汪叫!")

    def fetch(self):
        print(f"{self.name} 正在捡球!")

# Cat 类继承 Animal 类
class Cat(Animal):
    def __init__(self, name, age, color):
        super().__init__(name, age)
        self.color = color

    def speak(self):
        print(f"{self.name} 喵喵叫!")

    def climb(self):
        print(f"{self.name} 正在爬树!")

# 使用
dog = Dog("旺财", 3, "金毛")
cat = Cat("咪咪", 2, "白色")

dog.speak()  # 旺财 汪汪叫!
dog.eat()    # 动物在吃东西
dog.fetch()  # 旺财 正在捡球!

cat.speak()  # 咪咪 喵喵叫!
cat.eat()    # 动物在吃东西
cat.climb()  # 咪咪 正在爬树!

多重继承

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

class Flyable:
    def fly(self):
        print("会飞")

class Swimmable:
    def swim(self):
        print("会游泳")

class Duck(Flyable, Swimmable):
    pass

# Duck 类同时拥有 fly 和 swim 方法
duck = Duck()
duck.fly()   # 会飞
duck.swim()  # 会游泳

super() 函数

super() 用于调用父类的方法。

class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类的 __init__
        self.breed = breed

    def introduce(self):
        super().introduce()  # 调用父类方法
        print(f"品种:{self.breed}")

class Animal:
    def introduce(self):
        print(f"我是 {self.name}")

dog = Dog("旺财", "金毛")
dog.introduce()

多态

多态的概念

多态是指同一接口,不同实现。子类可以重写父类的方法,实现不同的行为。

方法重写

class Shape:
    def area(self):
        print("计算面积")

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

# 使用多态
shapes = [
    Rectangle(5, 3),
    Circle(4)
]

for shape in shapes:
    print(f"面积:{shape.area()}")

接口概念(抽象类)

Python 通过抽象类实现接口概念。

from abc import ABC, abstractmethod

class Animal(ABC):
    """抽象基类"""

    @abstractmethod
    def speak(self):
        """必须实现的方法"""
        pass

    @abstractmethod
    def move(self):
        """必须实现的方法"""
        pass

class Dog(Animal):
    def speak(self):
        print("汪汪叫")

    def move(self):
        print("四条腿走路")

class Cat(Animal):
    def speak(self):
        print("喵喵叫")

    def move(self):
        print("四肢着地走")

# 可以直接创建 Animal 的实例
animal = Dog()
animal.speak()  # 汪汪叫
animal.move()   # 四条腿走路

# animal = Animal()  # 报错:不能直接实例化抽象类

抽象类

抽象类和抽象方法

抽象类是不能被实例化的类,用于定义接口。

from abc import ABC, abstractmethod

class Vehicle(ABC):
    """交通工具抽象类"""

    @abstractmethod
    def start(self):
        """启动"""
        pass

    @abstractmethod
    def stop(self):
        """停止"""
        pass

    def honk(self):
        """鸣笛(具体方法)"""
        print("哔哔!")

class Car(Vehicle):
    def start(self):
        print("汽车启动")

    def stop(self):
        print("汽车停止")

class Motorcycle(Vehicle):
    def start(self):
        print("摩托车启动")

    def stop(self):
        print("摩托车停止")

# 使用
car = Car()
car.start()    # 汽车启动
car.honk()     # 哔哔!
car.stop()     # 汽车停止

motorcycle = Motorcycle()
motorcycle.start()    # 摩托车启动
motorcycle.honk()     # 哔哔!
motorcycle.stop()     # 摩托车停止

# vehicle = Vehicle()  # 报错:不能实例化抽象类

抽象属性

from abc import ABC, abstractmethod

class Employee(ABC):
    @property
    @abstractmethod
    def salary(self):
        """抽象属性"""
        pass

class FullTimeEmployee(Employee):
    @property
    def salary(self):
        return 10000

class PartTimeEmployee(Employee):
    @property
    def salary(self):
        return 5000

# 使用
ft = FullTimeEmployee()
print(ft.salary)  # 10000

pt = PartTimeEmployee()
print(pt.salary)  # 5000

实用练习

练习1:银行系统

class BankAccount:
    def __init__(self, account_number, balance=0):
        self.account_number = account_number
        self._balance = 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 > 0 and amount <= self._balance:
            self._balance -= amount
            print(f"取款 {amount} 成功,余额:{self._balance}")
        else:
            print("取款失败:金额无效或余额不足")

    def get_balance(self):
        return self._balance

class SavingsAccount(BankAccount):
    def __init__(self, account_number, balance=0, interest_rate=0.03):
        super().__init__(account_number, balance)
        self.interest_rate = interest_rate

    def add_interest(self):
        interest = self._balance * self.interest_rate
        self._balance += interest
        print(f"利息 {interest:.2f} 已添加,余额:{self._balance:.2f}")

class CheckingAccount(BankAccount):
    def __init__(self, account_number, balance=0, overdraft_limit=1000):
        super().__init__(account_number, balance)
        self.overdraft_limit = overdraft_limit

    def withdraw(self, amount):
        if amount > 0 and amount <= self._balance + self.overdraft_limit:
            self._balance -= amount
            print(f"取款 {amount} 成功,余额:{self._balance}")
        else:
            print(f"取款失败:超过透支限额 {self.overdraft_limit}")

# 使用
savings = SavingsAccount("123456", 1000, 0.05)
savings.deposit(500)
savings.add_interest()  # 利息 75.00 已添加

checking = CheckingAccount("789012", 500, 1000)
checking.withdraw(1200)  # 超过透支限额
checking.withdraw(600)   # 成功

练习2:学生管理系统

class Student:
    def __init__(self, student_id, name, age, grade):
        self.student_id = student_id
        self.name = name
        self.age = age
        self.grade = grade

    def get_info(self):
        return f"{self.name}({self.age}岁,{self.grade}年级)"

class UndergraduateStudent(Student):
    def __init__(self, student_id, name, age, grade, major):
        super().__init__(student_id, name, age, grade)
        self.major = major

    def get_info(self):
        return f"{self.name}({self.age}岁,{self.grade}年级,{self.major}专业)"

class GraduateStudent(Student):
    def __init__(self, student_id, name, age, grade, advisor):
        super().__init__(student_id, name, age, grade)
        self.advisor = advisor

    def get_info(self):
        return f"{self.name}({self.age}岁,{self.grade}年级,导师:{self.advisor})"

class StudentManager:
    def __init__(self):
        self.students = {}

    def add_student(self, student):
        self.students[student.student_id] = student
        print(f"已添加学生:{student.get_info()}")

    def get_student(self, student_id):
        return self.students.get(student_id, None)

    def get_all_students(self):
        return self.students.values()

# 使用
manager = StudentManager()

undergrad = UndergraduateStudent("001", "张三", 20, "大三", "计算机科学")
grad = GraduateStudent("002", "李四", 25, "研二", "王教授")

manager.add_student(undergrad)
manager.add_student(grad)

for student in manager.get_all_students():
    print(student.get_info())

练习3:图形形状系统

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass

    def describe(self):
        return f"面积:{self.area()}, 周长:{self.perimeter()}"

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 Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

    def perimeter(self):
        return 2 * 3.14 * self.radius

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 (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5

    def perimeter(self):
        return self.a + self.b + self.c

# 使用
shapes = [
    Rectangle(5, 3),
    Circle(4),
    Triangle(3, 4, 5)
]

for shape in shapes:
    print(shape.describe())

总结

今天我们学习了:

面向对象编程基础:OOP 的概念和三大特性
类和对象:类的定义、对象的创建和实例化
构造函数__init__ 方法和初始化
属性和方法:实例属性、类方法、静态方法
封装:私有属性、Getter 和 Setter
继承:继承父类、多重继承、super() 函数
多态:方法重写、抽象类和接口
抽象类ABC 基类、抽象方法和属性

重要概念

  1. 类 vs 对象:类是模板,对象是实例
  2. self:代表对象实例本身
  3. 继承:代码复用,建立类之间的关系
  4. 多态:同一接口,不同实现
  5. 封装:隐藏内部实现,只暴露必要接口

OOP 设计原则

  • 单一职责原则:一个类只做一件事
  • 开闭原则:对扩展开放,对修改关闭
  • 里氏替换原则:子类可以替换父类
  • 接口隔离原则:使用小接口
  • 依赖倒置原则:依赖抽象而不是具体实现

下次学习预告

下一篇我们将学习:

  • 文件操作进阶(JSON、CSV、Excel处理)
  • 装饰器(Decorators)
  • 生成器和迭代器
  • 常用标准库模块

恭喜你掌握了面向对象编程!你已经能设计复杂的应用程序了!

动物装饰