从0开始转入Ai应用层,从python学起第十二天
·
一、多继承
核心概念:一个子类可以同时继承多个父类的属性和方法。
基本格式:
class 子类(父类1, 父类2, ...):
pass
基础示例(能力组合):
class RobotMove:
def move(self):
print("移动")
class RobotSpeak:
def speak(self):
print("说话")
class RobotWork:
def work(self):
print("工作")
class Robot(RobotMove, RobotSpeak, RobotWork):
def serve(self):
self.move()
self.speak()
self.work()
robot = Robot()
robot.move() # 移动
robot.speak() # 说话
robot.work() # 工作
二、菱形问题与MRO
菱形问题:当B和C都继承了A,D又继承B和C时,D调用A的方法到底走哪条路?
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
class C(A):
def show(self):
print("C")
class D(B, C):
pass
d = D()
d.show() # B(按MRO顺序,B在C前面)
MRO(方法解析顺序):Python解决菱形问题的规则。
- 顺序优先:括号里先写的父类优先级更高
- 查看方式:
类名.mro()或类名.__mro__
print(D.mro()) # D -> B -> C -> A -> object
调整继承顺序改变结果:
class D(C, B): # C在前
pass
d = D()
d.show() # C(因为C在MRO中排在B前面)
三、super() 在多继承中的作用
核心理解:super() 不是调用“父类”,而是按MRO顺序调用下一个类的方法。
class A:
def show(self):
print("A")
class B(A):
def show(self):
super().show()
print("B")
class C(A):
def show(self):
super().show()
print("C")
class D(B, C):
pass
d = D()
d.show()
# 输出:A -> C -> B
# 流程:D.show() -> B.show() -> C.show() -> A.show()
# 回到C打印C -> 回到B打印B
执行流程解析:
- D没有show,按MRO找B
- B的show调用super(),按MRO找C
- C的show调用super(),按MRO找A
- A打印"A",返回C打印"C",返回B打印"B"
四、多继承使用建议
- 避免多继承:能用“组合”替代就不用继承。
- 明确继承顺序:必须用多继承时,先用
mro()确认查找顺序。 - 拆分单一职责父类:每个父类只负责一个功能(如Move只处理移动)。
- 避免菱形继承:不要设计多层嵌套的多继承结构。
组合替代多继承示例:
class ServiceRobot:
def __init__(self):
self.movable = Movable()
self.speakable = Speakable()
self.workable = Workable()
def serve(self):
self.movable.move()
self.speakable.speak()
self.workable.work()
五、方法重写
核心概念:子类定义与父类同名的方法,覆盖父类逻辑,实现“个性化”行为。
基础示例:
class Shape:
def area(self):
print("计算形状的面积")
class Circle(Shape):
def area(self):
print("计算圆形的面积")
c = Circle()
c.area() # 计算圆形的面积
重写时调用父类原方法(super()):
class Circle(Shape):
def area(self):
super().area() # 调用父类方法
print("计算圆形的面积") # 扩展自己的逻辑
c = Circle()
c.area()
# 输出:计算形状的面积 -> 计算圆形的面积
重写构造方法(init):
class User1:
def __init__(self, name, age):
self.name = name
self.age = age
class User(User1):
def __init__(self, name, age, sex):
super().__init__(name, age) # 必须先初始化父类属性
self.sex = sex
user = User("张三", 12, '男')
print(user.name, user.age, user.sex) # 张三 12 男
参数灵活处理:
class User1:
def say_hello(self, name):
print(f"{name}")
class User(User1):
def say_hello(self, name, sex="子类"):
print(f"{sex}, {name}")
u = User()
u.say_hello("你好") # 子类, 你好
u.say_hello("你好", "自定义") # 自定义, 你好
六、方法重写 vs 方法重载
| 特性 | 方法重写(Override) | 方法重载(Overload) |
|---|---|---|
| 定义 | 子类重写父类同名方法 | 同一类中多个同名但参数不同的方法 |
| Python支持 | 完全支持 | 不原生支持(可用默认参数模拟) |
| 核心目的 | 实现多态,子类个性化 | 灵活处理不同参数 |
模拟方法重载:
class Calculator:
def add(self, a, b, c=None):
if c is None:
return a + b
return a + b + c
calc = Calculator()
print(calc.add(1, 2)) # 3
print(calc.add(1, 2, 3)) # 6
七、类属性与私有方法
1. 类的私有属性
用双下划线 __ 开头定义,外部不能直接访问。Python会进行名称改编,变成 _类名__属性名。
class User:
def __init__(self, name, age, sex):
self.name = name # 公开属性
self._age = age # 保护属性(约定)
self.__sex = sex # 私有属性
def show(self):
print(f"姓名:{self.name}, 年龄:{self._age}, 性别:{self.__sex}")
p1 = User("张三", 18, "男")
print(p1.name) # 可访问
print(p1._age) # 可访问但不建议
# print(p1.__sex) # 报错!
print(p1._User__sex) # 通过名称改编访问(不推荐)
2. 类的私有方法
用双下划线 __ 开头定义,只能在类内部通过 self 调用,外部无法直接调用。
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def show(self): # 公开方法
self.__check_age() # 内部调用私有方法
def __check_age(self): # 私有方法
if self.age < 18:
print(f"{self.name}未满18岁")
else:
print(f"{self.name}已满18岁")
p1 = User("张三", 16)
p1.show() # 张三未满18岁
# p1.__check_age() # 报错!
私有方法的适用场景:类内部的辅助逻辑、不想对外暴露的核心逻辑。
3. self 参数详解
self是实例方法的第一个参数,代表当前对象实例- 调用时Python自动传入,无需手动传参
self不是关键字,可改为其他名字,但约定用self- 核心作用:通过
self.属性名访问/修改当前实例的属性,实现不同实例的数据隔离
class User:
def show(self): # self 必须写
print(f"姓名:{self.name}")
def get_name(this): # 可改名为 this(不推荐)
return this.name
八、类的专有方法(魔术方法)
核心概念:以 __ 开头结尾的特殊方法,由Python自动触发,让自定义类支持内置操作。
核心专有方法速查表:
| 方法名 | 触发场景 | 核心作用 |
|---|---|---|
__init__ |
创建实例时 | 初始化实例属性(构造方法) |
__str__ |
print(实例) / str(实例) |
定义友好字符串展示 |
__repr__ |
交互式环境 / repr(实例) |
定义调试字符串 |
__add__ |
实例 + 实例 |
重载加法运算符 |
__sub__ |
实例 - 实例 |
重载减法运算符 |
__len__ |
len(实例) |
定义长度逻辑 |
__getitem__ |
实例[索引] |
支持索引访问 |
__setitem__ |
实例[索引] = 值 |
支持索引赋值 |
__del__ |
实例被销毁时 | 清理资源(析构方法) |
__eq__ |
实例 == 实例 |
定义相等判断逻辑 |
实用示例(索引访问):
class BookShelf:
def __init__(self, books):
self.books = books
def __getitem__(self, index):
return self.books[index]
def __setitem__(self, index, value):
self.books[index] = value
shelf = BookShelf(["Python", "Java", "C++"])
print(shelf[0]) # Python(触发 __getitem__)
shelf[1] = "JavaScript" # 触发 __setitem__
print(shelf.books) # ['Python', 'JavaScript', 'C++']
今日核心总结
-
多继承:
- 子类可继承多个父类,继承顺序决定MRO优先级
- 菱形问题用MRO解决,用
mro()查看顺序 super()按MRO顺序调用下一个类的方法- 优先用组合替代多继承
-
方法重写:
- 子类覆盖父类同名方法,实现个性化逻辑
- 重写
__init__必须调用super().__init__() - 用
super().方法名()复用父类逻辑
-
私有属性与方法:
__属性名:私有属性,外部不可直接访问(名称改编)__方法名:私有方法,只能在类内部调用- Python通过“约定”而非强制实现私有
-
专有方法(魔术方法):
__xxx__格式,Python自动触发- 让自定义类支持内置操作(打印、索引、运算等)
- 最常用:
__init__、__str__、__getitem__
注:已经使用DeepSeek进行整理精简核心内容,些许不理解的配合个人笔记进行理解。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)