Veloris.
返回索引
概念基础 2026-02-14

Python面向对象编程:class比C的struct强在哪?继承、多态一篇讲清

3 分钟
928 words

Python面向对象编程:class比C的struct强在哪?继承、多态一篇讲清

面向对象编程(OOP)是一种重要的编程范式。虽然Python支持多种编程风格,但理解OOP对于阅读他人代码和使用第三方库非常重要。本篇标记为选修/后置,你可以在掌握基础后按需学习。


1. 面向对象基础概念

概念说明类比
类(Class)对象的模板/蓝图汽车设计图
对象(Object)类的实例具体的一辆汽车
属性(Attribute)对象的数据汽车的颜色、品牌
方法(Method)对象的行为汽车的启动、刹车
封装(Encapsulation)隐藏内部实现不需要知道发动机原理也能开车
继承(Inheritance)子类继承父类特性电动汽车继承汽车的基本特性
多态(Polymorphism)同一接口不同实现不同品牌汽车的启动方式

2. 类与对象

2.1 定义类

class Person:
    """人员类"""
    
    # 类属性(所有实例共享)
    species = "人类"
    
    # 初始化方法(构造函数)
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age
    
    # 实例方法
    def introduce(self):
        return f"我是{self.name},今年{self.age}岁"
    
    def have_birthday(self):
        self.age += 1
        print(f"{self.name}过生日了,现在{self.age}岁")

2.2 创建对象

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

# 访问属性
print(person1.name)      # 张三
print(person1.age)       # 25
print(person1.species)   # 人类

# 调用方法
print(person1.introduce())  # 我是张三,今年25岁
person1.have_birthday()     # 张三过生日了,现在26岁

# 修改属性
person1.age = 28
person1.city = "北京"  # 动态添加属性

2.3 实例属性和类属性

class Counter:
    # 类属性:所有实例共享
    total_count = 0
    
    def __init__(self, name):
        # 实例属性:每个实例独有
        self.name = name
        self.count = 0
        Counter.total_count += 1
    
    def increment(self):
        self.count += 1

# 测试
c1 = Counter("计数器1")
c2 = Counter("计数器2")

c1.increment()
c1.increment()
c2.increment()

print(c1.count)           # 2(实例属性)
print(c2.count)           # 1(实例属性)
print(Counter.total_count) # 2(类属性)

3. 方法类型

class MyClass:
    class_var = "类变量"
    
    def __init__(self, value):
        self.instance_var = value
    
    # 实例方法:第一个参数是self
    def instance_method(self):
        return f"实例方法,访问{self.instance_var}"
    
    # 类方法:第一个参数是cls
    @classmethod
    def class_method(cls):
        return f"类方法,访问{cls.class_var}"
    
    # 静态方法:没有self或cls
    @staticmethod
    def static_method(x, y):
        return f"静态方法,计算{x + y}"

# 使用
obj = MyClass("实例变量值")

print(obj.instance_method())      # 实例方法
print(MyClass.class_method())     # 类方法
print(obj.class_method())         # 也可以通过实例调用
print(MyClass.static_method(1, 2)) # 静态方法
方法类型装饰器第一个参数用途
实例方法self操作实例数据
类方法@classmethodcls操作类数据,工厂方法
静态方法@staticmethod工具函数,与类相关但不需要访问类/实例

4. 封装

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner          # 公开属性
        self._balance = balance     # 约定私有(单下划线)
        self.__pin = "1234"         # 名称修饰(双下划线)
    
    # 属性访问器(getter)
    @property
    def balance(self):
        return self._balance
    
    # 属性设置器(setter)
    @balance.setter
    def balance(self, value):
        if value < 0:
            raise ValueError("余额不能为负")
        self._balance = value
    
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            return True
        return False

# 使用
account = BankAccount("张三", 1000)
print(account.balance)      # 1000(通过property访问)
account.balance = 2000      # 通过setter设置
# account.balance = -100    # ValueError

account.deposit(500)
print(account.balance)      # 2500

# 访问约定私有属性(不推荐但可以)
print(account._balance)     # 2500

# 访问名称修饰属性
# print(account.__pin)      # AttributeError
print(account._BankAccount__pin)  # 1234(可以但强烈不推荐)

5. 继承

# 父类(基类)
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("子类必须实现此方法")
    
    def move(self):
        print(f"{self.name}在移动")

# 子类
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类构造函数
        self.breed = breed
    
    def speak(self):
        return f"{self.name}说:汪汪!"
    
    def fetch(self):
        return f"{self.name}在捡球"

class Cat(Animal):
    def speak(self):
        return f"{self.name}说:喵喵!"

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

print(dog.speak())   # 旺财说:汪汪!
print(cat.speak())   # 咪咪说:喵喵!
dog.move()           # 旺财在移动(继承的方法)
print(dog.fetch())   # 旺财在捡球(子类特有方法)

# 检查继承关系
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Animal))  # True
print(issubclass(Dog, Animal))  # True

# 多重继承
class FlyingAnimal:
    def fly(self):
        print("飞行中...")

class Bird(Animal, FlyingAnimal):
    def speak(self):
        return f"{self.name}说:叽叽!"

bird = Bird("小鸟")
bird.fly()  # 飞行中...

6. 多态

class Shape:
    def area(self):
        raise NotImplementedError

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):
        import math
        return math.pi * self.radius ** 2

# 多态:同一接口,不同实现
def print_area(shape):
    print(f"面积:{shape.area():.2f}")

shapes = [Rectangle(3, 4), Circle(5), Rectangle(2, 6)]
for shape in shapes:
    print_area(shape)
# 面积:12.00
# 面积:78.54
# 面积:12.00

# Python的鸭子类型
# "如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子"
class Duck:
    def quack(self):
        print("嘎嘎")

class Person:
    def quack(self):
        print("我在模仿鸭子:嘎嘎")

def make_it_quack(thing):
    thing.quack()  # 不关心类型,只关心有没有quack方法

make_it_quack(Duck())    # 嘎嘎
make_it_quack(Person())  # 我在模仿鸭子:嘎嘎

7. 魔术方法

魔术方法(Magic Methods)是以双下划线开头和结尾的特殊方法。

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!r}, {self.y!r})"
    
    # 运算符重载
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    # 比较运算
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __lt__(self, other):
        return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
    
    # 长度
    def __len__(self):
        return 2
    
    # 索引访问
    def __getitem__(self, index):
        if index == 0:
            return self.x
        elif index == 1:
            return self.y
        raise IndexError("索引超出范围")
    
    # 布尔值
    def __bool__(self):
        return self.x != 0 or self.y != 0

# 使用
v1 = Vector(3, 4)
v2 = Vector(1, 2)

print(v1)           # Vector(3, 4)
print(v1 + v2)      # Vector(4, 6)
print(v1 - v2)      # Vector(2, 2)
print(v1 * 2)       # Vector(6, 8)
print(v1 == Vector(3, 4))  # True
print(v1[0])        # 3
print(len(v1))      # 2
print(bool(Vector(0, 0)))  # False
魔术方法用途触发方式
__init__初始化obj = Class()
__str__字符串表示str(obj), print(obj)
__repr__开发者表示repr(obj)
__add__加法obj1 + obj2
__eq__相等比较obj1 == obj2
__len__长度len(obj)
__getitem__索引访问obj[i]
__iter__迭代for x in obj
__call__调用obj()

8. 数据类(dataclass)

Python 3.7+引入的dataclass简化了数据类的定义。

from dataclasses import dataclass, field
from typing import List

@dataclass
class Point:
    x: float
    y: float

# 自动生成__init__, __repr__, __eq__等方法
p1 = Point(3, 4)
p2 = Point(3, 4)
print(p1)           # Point(x=3, y=4)
print(p1 == p2)     # True

@dataclass
class Person:
    name: str
    age: int
    city: str = "北京"  # 默认值
    hobbies: List[str] = field(default_factory=list)  # 可变默认值

person = Person("张三", 25)
print(person)  # Person(name='张三', age=25, city='北京', hobbies=[])

# 不可变数据类
@dataclass(frozen=True)
class ImmutablePoint:
    x: float
    y: float

p = ImmutablePoint(1, 2)
# p.x = 3  # FrozenInstanceError

# 带方法的数据类
@dataclass
class Rectangle:
    width: float
    height: float
    
    @property
    def area(self):
        return self.width * self.height

rect = Rectangle(3, 4)
print(rect.area)  # 12

9. 与C语言结构体对比

// C语言结构体
struct Person {
    char name[50];
    int age;
    char city[50];
};

// 使用
struct Person p1;
strcpy(p1.name, "张三");
p1.age = 25;
strcpy(p1.city, "北京");
# Python类
class Person:
    def __init__(self, name, age, city="北京"):
        self.name = name
        self.age = age
        self.city = city
    
    def introduce(self):
        return f"我是{self.name}"

# 或使用dataclass
@dataclass
class Person:
    name: str
    age: int
    city: str = "北京"

# 使用
p1 = Person("张三", 25)
特性C结构体Python类
数据封装仅数据数据+方法
类型检查编译时运行时(可选类型提示)
内存管理手动自动
继承不支持支持
方法不支持支持

10. 实战练习

练习:简单的任务管理器

"""
练习:实现一个简单的任务管理器
"""
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional
from enum import Enum

class TaskStatus(Enum):
    PENDING = "待处理"
    IN_PROGRESS = "进行中"
    COMPLETED = "已完成"

@dataclass
class Task:
    title: str
    description: str = ""
    status: TaskStatus = TaskStatus.PENDING
    created_at: datetime = field(default_factory=datetime.now)
    completed_at: Optional[datetime] = None
    
    def complete(self):
        self.status = TaskStatus.COMPLETED
        self.completed_at = datetime.now()
    
    def start(self):
        self.status = TaskStatus.IN_PROGRESS

class TaskManager:
    def __init__(self):
        self._tasks: List[Task] = []
    
    def add_task(self, title: str, description: str = "") -> Task:
        task = Task(title, description)
        self._tasks.append(task)
        return task
    
    def get_tasks(self, status: Optional[TaskStatus] = None) -> List[Task]:
        if status is None:
            return self._tasks.copy()
        return [t for t in self._tasks if t.status == status]
    
    def get_pending_count(self) -> int:
        return len(self.get_tasks(TaskStatus.PENDING))
    
    def __len__(self):
        return len(self._tasks)
    
    def __iter__(self):
        return iter(self._tasks)

# 使用
if __name__ == "__main__":
    manager = TaskManager()
    
    task1 = manager.add_task("学习Python", "完成面向对象章节")
    task2 = manager.add_task("写代码", "实现任务管理器")
    
    task1.start()
    task2.complete()
    
    print(f"总任务数:{len(manager)}")
    print(f"待处理:{manager.get_pending_count()}")
    
    for task in manager:
        print(f"- {task.title}: {task.status.value}")

11. 总结

🔑 核心要点

知识点要点
类与对象类是模板,对象是实例
属性实例属性(self.x)和类属性
方法实例方法、类方法、静态方法
封装使用_和__约定私有,property控制访问
继承子类继承父类,super()调用父类
多态同一接口不同实现,鸭子类型
魔术方法自定义运算符和内置函数行为
dataclass简化数据类定义

✅ 学习检查清单

  • 能定义类和创建对象
  • 理解实例属性和类属性的区别
  • 掌握三种方法类型
  • 理解封装和property的使用
  • 能实现简单的继承
  • 了解常用魔术方法
  • 能使用dataclass

📖 下一步学习

掌握了面向对象编程后,让我们学习Python的迭代器与生成器:


常见问题 FAQ

💬 Python写脚本也需要用class吗?

不一定。简单脚本用函数就够了。class适合需要管理状态的场景,或者你需要复用代码和构建大型项目时。但读懂class是必须的,因为第三方库大量使用OOP。

💬 Python有私有变量吗?

没有真正的private。_name是约定的”内部使用”,__name会触发名称改写(name mangling),但仍可通过_ClassName__name访问。Python信奉”我们都是成年人”。


系列导航

End of file.