Python 面向对象核心实战:封装、继承、多态、抽象类、枚举、单例完整示例
本文把 Python 面向对象高频知识点全部落地,包含:封装继承多态、多继承、抽象类、枚举类、访问权限、属性封装、单例模式(构造函数 / 装饰器两种写法),全部可直接运行。
目录
前言
1. 封装、继承、多态基础案例
2. 多继承
3. 抽象类
4. 枚举类
5. 数据的访问级别
6. 属性的封装 @property
7. 单例类:构造函数写法 + 装饰器写法
方式 1:重写__new__构造函数实现单例
方式 2:装饰器实现单例
总结速查表
拓展思考
前言
面向对象编程 (OOP) 是 Python 开发的核心,封装、继承、多态是三大基石;除此之外多继承、抽象类、枚举、访问控制、property 属性封装、单例模式,都是项目里高频出现的技术点。下面每个知识点附带可运行完整代码。
1. 封装、继承、多态基础案例
- 封装:把属性和方法放到类内部,对外隐藏内部细节
- 继承:子类复用父类代码,扩展自己功能
- 多态:不同子类重写父类同名方法,调用时执行各自逻辑
python
运行
class Animal: """父类:动物""" def __init__(self, name): # 封装:把name封装到实例内部 self.name = name def speak(self): """父类方法,留给子类重写""" raise NotImplementedError("子类必须实现speak方法") class Dog(Animal): def speak(self): print(f"{self.name}:汪汪汪") class Cat(Animal): def speak(self): print(f"{self.name}:喵喵喵") # 多态:同一个方法,不同对象表现不同行为 def animal_sound(animal: Animal): animal.speak() if __name__ == "__main__": dog = Dog("小狗") cat = Cat("小猫") animal_sound(dog) animal_sound(cat)运行输出
plaintext
小狗:汪汪汪 小猫:喵喵喵2. 多继承
Python 支持一个类同时继承多个父类,注意 MRO 方法解析顺序。
python
运行
class A: def func(self): print("A类的func") class B: def func(self): print("B类的func") # 多继承:同时继承A、B class C(A, B): pass if __name__ == "__main__": c = C() c.func() # 查看继承搜索顺序MRO print(C.__mro__)注意:继承顺序
class C(A,B),查找方法优先找 A,找不到再找 B。
3. 抽象类
抽象类强制子类必须实现指定方法,自身不能实例化。Python 使用abc模块。
python
运行
from abc import ABC, abstractmethod class BasePay(ABC): """支付抽象类,定义规范""" @abstractmethod def pay(self, money): """子类必须实现pay方法""" pass class AliPay(BasePay): def pay(self, money): print(f"支付宝支付:{money}元") class WechatPay(BasePay): def pay(self, money): print(f"微信支付:{money}元") if __name__ == "__main__": # base = BasePay() # 抽象类不能实例化,会报错 ali = AliPay() ali.pay(100) wechat = WechatPay() wechat.pay(200)4. 枚举类
枚举用来定义一组固定常量,避免魔法数字,使用enum.Enum。
python
运行
from enum import Enum class StatusEnum(Enum): # 枚举常量 SUCCESS = 200 FAIL = 500 TIMEOUT = 408 if __name__ == "__main__": print(StatusEnum.SUCCESS) print(StatusEnum.SUCCESS.name) print(StatusEnum.SUCCESS.value) # 遍历所有枚举 for item in StatusEnum: print(item.name, item.value)5. 数据的访问级别
Python 没有真正私有,靠命名约定区分访问权限:
public:普通属性,外部随便访问_protected单下划线:保护,约定不要外部直接访问__private双下划线:私有,会发生名字重整,外部不能直接访问
python
运行
class Person: def __init__(self): self.name = "张三" # 公开 self._age = 20 # 保护 self.__id_card = "123456" # 私有 if __name__ == "__main__": p = Person() print(p.name) print(p._age) # print(p.__id_card) # 直接访问私有属性报错 # 实际被重命名为 _Person__id_card,仅做演示,不建议这么写 print(p._Person__id_card)约定:单下划线
_xxx不要在类外部读写;双下划线__xxx为私有,禁止外部访问。
6. 属性的封装 @property
使用@property把方法伪装成属性,实现 getter、setter,对属性赋值做校验,完成属性封装。
python
运行
class Student: def __init__(self): self.__score = 0 @property def score(self): """getter 获取分数""" return self.__score @score.setter def score(self, value): """setter 设置分数,增加校验逻辑""" if not isinstance(value, int): raise ValueError("分数必须是整数") if 0 <= value <= 100: self.__score = value else: raise ValueError("分数必须在0‑100之间") if __name__ == "__main__": s = Student() s.score = 88 print(s.score) # s.score = 200 # 会抛出异常7. 单例类:构造函数写法 + 装饰器写法
单例:整个程序中,这个类只能有一个实例对象。
方式 1:重写__new__构造函数实现单例
python
运行
class SingletonNew: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance if __name__ == "__main__": obj1 = SingletonNew() obj2 = SingletonNew() print(obj1 is obj2) # True,同一个对象方式 2:装饰器实现单例
python
运行
def singleton_decorator(cls): instance = {} def wrapper(*args, **kwargs): if cls not in instance: instance[cls] = cls(*args, **kwargs) return instance[cls] return wrapper @singleton_decorator class SingletonDecorator: pass if __name__ == "__main__": a1 = SingletonDecorator() a2 = SingletonDecorator() print(a1 is a2) # True总结速查表
表格
| 知识点 | 核心要点 |
|---|---|
| 封装 | 把属性方法封装在类内部,对外隐藏细节 |
| 继承 | 子类复用父类代码,class Son(Father) |
| 多态 | 不同子类重写同一方法,调用表现不同行为 |
| 多继承 | class C(A,B),MRO 决定方法查找顺序 |
| 抽象类 | ABC+@abstractmethod,强制子类实现方法,不能实例化 |
| 枚举类 | Enum,管理固定常量,消除魔法数字 |
| 访问级别 | 公开、_保护、__私有,命名约定控制访问 |
| 属性封装 | @property,把方法当属性,做赋值校验 |
| 单例 | __new__重写 / 装饰器,保证全局唯一实例 |
拓展思考
- 多继承场景下 MRO 顺序怎么看?
类名.__mro__ - @property 除了 setter,还有 deleter 删除属性
- 单例模式在多线程下会有线程安全问题,需要加锁。
