一、为什么需要面向对象
面向对象程序设计(OOP)的核心思想是把数据和操作数据的行为封装在一起,用“对象”来模拟现实世界中的实体。Python 是一门支持多范式编程的语言,但它的面向对象特性非常自然、灵活,几乎一切皆对象。
二、类与对象:一切的起点
在讲方法之前,先明确类(class)和对象(object)的关系:类是对一类事物的抽象描述,对象是类的具体实例。
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赋值,每个对象各自独立。
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 类属性
类属性定义在类体中、方法之外,被所有实例共享,适合存放常量或全局统计信息。
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可以实现受控的属性访问。
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,可以访问实例属性和类属性。
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.566364.2 类方法
用@classmethod装饰,第一个参数是cls,常用于提供替代构造器。
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) # 张三 204.3 静态方法
用@staticmethod装饰,既不需要self也不需要cls,本质上是放在类命名空间里的普通函数。
class MathUtil: @staticmethod def is_even(n): return n % 2 == 0 print(MathUtil.is_even(10)) # True4.4 三种方法对比
| 类型 | 装饰器 | 第一个参数 | 典型用途 |
|---|---|---|---|
| 实例方法 | 无 | self | 操作实例数据 |
| 类方法 | @classmethod | cls | 替代构造器、操作类状态 |
| 静态方法 | @staticmethod | 无 | 工具函数、与实例无关的逻辑 |
五、继承:复用与扩展
5.1 基本继承
子类继承父类的属性和方法,并可在此基础上扩展或重写。
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__()完成父类初始化。
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) # 麻雀 True5.3 多重继承与 MRO
Python 支持多重继承,方法查找顺序由 MRO(方法解析顺序)决定,可用类名.__mro__查看。
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 是动态类型语言,天然支持“鸭子类型”:只要对象有对应方法即可调用,不要求继承关系。
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 基于继承的多态
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七、综合实例:一个简单的员工管理系统
下面把方法、属性、继承与多态综合起来,实现一个可运行的示例。
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类,体会多态带来的扩展便利。