Python 面向对象编程:方法、属性、继承与多态详解

一、为什么需要面向对象

面向对象程序设计(OOP)的核心思想是把数据和操作数据的行为封装在一起,用"对象"来模拟现实世界中的实体。Python 是一门支持多范式编程的语言,但它的面向对象特性非常自然、灵活,几乎一切皆对象。

二、类与对象:一切的起点

在讲方法之前,先明确类(class)和对象(object)的关系:类是对一类事物的抽象描述,对象是类的具体实例。

python 复制代码
class Dog:
    """一个最简单的类"""
def __init__(self, name, age):
    self.name = name
    self.age = age
创建对象(实例化)
d = Dog("旺财", 3)
print(d.name, d.age)  # 旺财 3

其中 __init__ 是构造方法,在创建对象时自动调用,用于初始化属性。

三、属性:实例属性与类属性

3.1 实例属性

实例属性定义在 __init__ 中,通过 self.xxx 赋值,每个对象各自独立。

python 复制代码
class Student:
    def __init__(self, name, score):
        self.name = name      # 实例属性
        self.score = score    # 实例属性
s1 = Student("小明", 90)
s2 = Student("小红", 85)
s1.score = 95
print(s1.score, s2.score)  # 95 85,互不影响

3.2 类属性

类属性定义在类体中、方法之外,被所有实例共享,适合存放常量或全局统计信息。

python 复制代码
class Student:
    school = "第一中学"   # 类属性
    count = 0             # 类属性,用于统计实例数量
def __init__(self, name):
    self.name = name
    Student.count += 1
a = Student("小明")
b = Student("小红")
print(Student.school)   # 第一中学
print(Student.count)    # 2

注意:通过实例修改类属性只会创建同名实例属性,不会影响类本身。修改类属性应使用 类名.属性名。

3.3 私有属性与 property

Python 用下划线约定表示访问级别:_name 表示受保护,__name 表示私有(名称改写)。配合 @property 可以实现受控的属性访问。

python 复制代码
class Account:
    def __init__(self, balance):
        self.__balance = balance   # 私有属性
@property
def balance(self):
    """只读属性"""
    return self.__balance

@balance.setter
def balance(self, value):
    if value < 0:
        raise ValueError("余额不能为负")
    self.__balance = value
acc = Account(100)
acc.balance = 200
print(acc.balance)   # 200
acc.balance = -1   # 抛出 ValueError

四、方法:实例方法、类方法与静态方法

4.1 实例方法

最常见的类型,第一个参数是 self,可以访问实例属性和类属性。

python 复制代码
class Circle:
    def __init__(self, r):
        self.r = r
def area(self):          # 实例方法
    return 3.14159 * self.r ** 2
c = Circle(2)
print(c.area())   # 12.56636

4.2 类方法

用 @classmethod 装饰,第一个参数是 cls,常用于提供替代构造器。

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
@classmethod
def from_string(cls, info):
    """从 'name-age' 字符串创建对象"""
    name, age = info.split("-")
    return cls(name, int(age))
p = Person.from_string("张三-20")
print(p.name, p.age)   # 张三 20

4.3 静态方法

用 @staticmethod 装饰,既不需要 self 也不需要 cls,本质上是放在类命名空间里的普通函数。

python 复制代码
class MathUtil:
    @staticmethod
    def is_even(n):
        return n % 2 == 0
print(MathUtil.is_even(10))   # True

4.4 三种方法对比

类型 装饰器 第一个参数 典型用途
实例方法 无 self 操作实例数据
类方法 @classmethod cls 替代构造器、操作类状态
静态方法 @staticmethod 无 工具函数、与实例无关的逻辑

五、继承:复用与扩展

5.1 基本继承

子类继承父类的属性和方法,并可在此基础上扩展或重写。

python 复制代码
class Animal:
    def __init__(self, name):
        self.name = name
def speak(self):
    return "......"
class Cat(Animal):
def speak(self):          # 重写父类方法
return f"{self.name}:喵喵喵"
class Dog(Animal):
def speak(self):
return f"{self.name}:汪汪汪"
print(Cat("咪咪").speak())   # 咪咪:喵喵喵
print(Dog("旺财").speak())   # 旺财:汪汪汪

5.2 使用 super() 调用父类

子类重写 __init__ 时,通常需要调用 super().__init__() 完成父类初始化。

python 复制代码
class Animal:
    def __init__(self, name):
        self.name = name
class Bird(Animal):
def init(self, name, can_fly):
super().init(name)   # 调用父类构造方法
self.can_fly = can_fly
b = Bird("麻雀", True)
print(b.name, b.can_fly)   # 麻雀 True

5.3 多重继承与 MRO

Python 支持多重继承,方法查找顺序由 MRO(方法解析顺序)决定,可用 类名.__mro__ 查看。

python 复制代码
class A:
    def hello(self):
        return "A"
class B(A):
def hello(self):
return "B"
class C(A):
def hello(self):
return "C"
class D(B, C):
pass
print(D().hello())        # B
print([c.name for c in D.mro])   # ['D', 'B', 'C', 'A', 'object']

六、多态:同一接口,不同实现

多态指不同类的对象对同一方法调用做出不同响应。Python 是动态类型语言,天然支持"鸭子类型":只要对象有对应方法即可调用,不要求继承关系。

python 复制代码
class Cat:
    def speak(self):
        return "喵"
class Dog:
def speak(self):
return "汪"
class Duck:
def speak(self):
return "嘎"
def make_sound(animal):
print(animal.speak())
for a in [Cat(), Dog(), Duck()]:
make_sound(a)
喵
汪
嘎

可以看到,make_sound 并不关心传入对象的具体类型,只关心它是否有 speak 方法。这正是多态带来的灵活性。

6.1 基于继承的多态

python 复制代码
class Shape:
    def area(self):
        raise NotImplementedError
class Rectangle(Shape):
def init(self, w, h):
self.w, self.h = w, h
def area(self):
    return self.w * self.h
class Circle(Shape):
def init(self, r):
self.r = r
def area(self):
    return 3.14159 * self.r ** 2
shapes = [Rectangle(3, 4), Circle(2)]
for s in shapes:
print(f"{type(s).name} 面积:{s.area():.2f}")
Rectangle 面积:12.00
Circle 面积:12.57

七、综合实例:一个简单的员工管理系统

下面把方法、属性、继承与多态综合起来,实现一个可运行的示例。

python 复制代码
class Employee:
    """员工基类"""
    company = "示例科技"          # 类属性
def __init__(self, name, base_salary):
    self.name = name                    # 实例属性
    self.base_salary = base_salary

def salary(self):                       # 实例方法,供子类重写
    return self.base_salary

def __str__(self):
    return f"{self.name}({type(self).__name__})月薪:{self.salary():.2f}"
class Engineer(Employee):
def init(self, name, base_salary, bonus):
super().init(name, base_salary)
self.bonus = bonus
def salary(self):
    return self.base_salary + self.bonus
class Manager(Employee):
def init(self, name, base_salary, team_size):
super().init(name, base_salary)
self.team_size = team_size
def salary(self):
    return self.base_salary + self.team_size * 500
class Intern(Employee):
@classmethod
def create(cls, name):
"""类方法作为替代构造器"""
return cls(name, 3000)
@staticmethod
def is_valid_days(days):
    """静态方法:校验实习天数"""
    return 0 < days <= 180
employees = [
Engineer("张三", 15000, 3000),
Manager("李四", 20000, 3),
Intern.create("王五"),
]
total = 0
for e in employees:
print(e)                 # 多态:调用各自的 salary()
total += e.salary()
print(f"公司:{Employee.company},总人力成本:{total:.2f}")
print("实习天数合法:", Intern.is_valid_days(90))

运行结果:

复制代码
张三(Engineer)月薪:18000.00
李四(Manager)月薪:21500.00
王五(Intern)月薪:3000.00
公司:示例科技,总人力成本:42500.00
实习天数合法: True

八、常见误区与最佳实践

  • 不要滥用多重继承:优先使用组合(has-a)代替继承(is-a),结构更清晰。
  • 类属性不要用可变对象 :如 list、dict 作为类属性会被所有实例共享,容易踩坑。
  • 私有属性只是约定 :Python 没有真正的访问控制,__x 会被改名为 _类名__x。
  • 优先使用鸭子类型:不必为了多态强行设计继承体系,接口一致即可。
  • 善用 @property:在需要校验或计算属性时,比直接暴露字段更安全。

九、总结

本文从类与对象出发,依次讲解了实例属性与类属性、三种方法类型、单继承与多重继承、以及基于继承和鸭子类型的多态。掌握这些概念后,就能用 Python 写出结构清晰、易于扩展的面向对象代码。

建议读者把文中的综合实例动手敲一遍,并尝试新增一个 Sales 类,体会多态带来的扩展便利。

相关推荐
云边云科技_云网融合1 小时前
面向汽车零部件制造业场景的解决方案 | 70 秒:一台车下线的时间里,藏着五张网
开发语言·汽车·php
Evand J1 小时前
【PMSM滤波例程2】PMSM未知负载转矩观测EKF。MATLAB例程(负载增广EKF与实际仿真结果)。附下载链接
开发语言·matlab·电机
will_net1 小时前
apollo 站点部署&C#接入
开发语言·c#·apollo
威哥爱编程2 小时前
Python 智能体开发实战 05:一问教材内容它就编?先把答案从你自己的资料里检索出来
python·agent
java_prinln2 小时前
RAG 面试题介绍
python·agent
威哥爱编程2 小时前
Python 智能体开发实战 06:一个函数里塞了八百行?用状态机把批改流程拆成能回退的步骤
python·agent
晗夜未央2 小时前
任务队列反复失败,先分清重试、阻塞和结果待核对
开发语言·javascript
熊猫钓鱼>_>2 小时前
四种书签,一条时间线:一个读书 App 的记忆颗粒与它的边界案例【鸿蒙心迹】
开发语言·华为·ai编程·harmonyos·鸿蒙·openharmony·鸿蒙pc
努力努力再努力wz3 小时前
【Lua 入门系列】Lua 函数深入理解:函数对象、多返回值、可变参数、闭包、递归与尾调用优化
开发语言·lua