Yunyuzuiluo

Python 百战 入门 8 面向对象编程进阶 封装,继承,多态

继承

子类扩展父类

Python支持多重继承,一个子类可以继承多个父类
如果在类定义中没有指定父类,则默认父类是 object类

class 子类类名(父类1[,父类2,...]):
类体

构造函数

子类不重写 init ,实例化子类时,会自动调用父类定义的 init
子类重写了 init 时,实例化子类,就不会调用父类已经定义的 init
如果重写了 init 时,要使用父类的构造方法,可以使用 super 关键字,也可以使用如下格式调用:
父类名.init(self, 参数列表)

class Person:
def init(self, name, age): # Person类的构造方法,接收name和age
print("Person的构造方法") # 提示构造方法执行
self.name = name # 初始化实例变量name
self.age = age # 初始化实例变量age

def say_age(self):                                        # 定义方法say_age
    print(self.name, "的年龄是:", self.age)              # 打印姓名和年龄

class Student(Person): # Student继承Person
def init(self, name, age, score): # 子类构造方法,新增score
super(Student, self).init(name, age) # 调用父类构造方法
print("Student的构造方法") # 提示子类构造方法执行
self.score = score # 初始化子类特有变量score

s1 = Student("张三", 15, 85) # 创建Student实例
print(dir(s1)) # 打印对象属性和方法列表

类成员的继承和重写

1 成员继承:子类继承了父类除构造方法之外的所有成员。(私有属性、私有方法也被继承)
2 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”

class Person:
def init(self, name, age): # 人类基类构造方法
self.name = name # 初始化姓名属性
self.age = age # 初始化年龄属性

def say_age(self):                                # 年龄汇报方法
    print(self.name, "的年龄是:", self.age)      # 打印姓名和年龄信息

def say_name(self):                               # 姓名汇报方法(父类版本)
    print("我是", self.name)                      # 标准自我介绍格式

class Student(Person):
def init(self, name, age, score): # 学生类构造方法
Person.init(self, name, age) # 调用父类构造方法初始化基础属性
self.score = score # 新增分数属性初始化

def say_score(self):                             # 分数汇报方法(子类特有)
    print(self.name, "的分数是:", self.score)    # 打印姓名和分数信息

def say_name(self):                              # 重写父类的say_name方法
    print("报告老师,我是", self.name)           # 学生特有自我介绍格式

实例化测试
s1 = Student("张三", 15, 85) # 创建学生对象
s1.say_score() # 调用子类特有方法
s1.say_name() # 调用重写后的方法
s1.say_age() # 调用继承自父类的方法

object根类

object 类是所有类的父类,因此所有的类都有 object 类的属性和方法。

dir() 查看对象属性

重写 str() 方法

多重继承

class A:
def init(self):
print("A 初始化")

class B(A):
def init(self):
super().init()
print("B 初始化")

class C(A):
def init(self):
super().init()
print("C 初始化")

class D(B, C):
def init(self):
super().init()
print("D 初始化")

d = D() # 输出顺序:ACBD

MRO方法解析顺序

先左后右

super()获得父类定义

在子类中,如果想要获得父类的方法时,我们可以通过 super() 来做。super() 代表父类的定义,不是父类对象。
❤想调用父类的构造方法:
super(子类名称,self).init(参数列表)

多态

多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。
多态是方法的多态,属性没有多态。
多态的存在有2个必要条件:继承、方法重写

class Animal: # 定义动物基类
def shout(self): # 动物叫声方法
print("动物叫了一声") # 默认实现

class Dog(Animal): # 定义狗子类
def shout(self): # 重写叫声方法
print("小狗,汪汪汪") # 狗的特有叫声

class Cat(Animal): # 定义猫子类
def shout(self): # 重写叫声方法
print("小猫,喵喵喵") # 猫的特有叫声

def animal_shout(a: Animal): # 类型提示:接收Animal类型
"""多态演示函数:根据传入对象调用不同shout方法"""
a.shout() # 动态调用实际对象的shout方法

多态调用演示
animal_shout(Dog()) # 传入Dog对象,输出:小狗,汪汪汪
animal_shout(Cat()) # 传入Cat对象,输出:小猫,喵喵喵
animal_shout(Animal()) # 传入基类对象,输出:动物叫了一声

特殊方法和运算符重载

常见特殊方法


运算符重载

运算符重载示例

class Person:
def init(self, name):
self.name = name

def __add__(self, other):
    if isinstance(other, Person):
        return f"{self.name}--{other.name}"
    return "操作数类型错误"

def __mul__(self, other):
    if isinstance(other, int):
        return self.name * other
    return "操作数类型错误"

使用示例

运算符重载示例

class Person:
def init(self, name): # 初始化方法
self.name = name # 设置姓名属性

def __add__(self, other):  # 重载加法运算符
    if isinstance(other, Person):  # 检查是否为Person对象
        return f"{self.name}--{other.name}"  # 返回连接后的姓名
    return "操作数类型错误"  # 类型不匹配时返回错误

def __mul__(self, other):  # 重载乘法运算符
    if isinstance(other, int):  # 检查是否为整数
        return self.name * other  # 返回重复的姓名
    return "操作数类型错误"  # 类型不匹配时返回错误

使用示例
p1 = Person("高淇") # 创建第一个Person对象
p2 = Person("高希希") # 创建第二个Person对象

print(p1 + p2) # 调用加法运算符重载
print(p1 * 3) # 调用乘法运算符重载

特殊属性

ython对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。这里我们列出常见的特殊属性:

对象的浅拷贝和深拷贝

import copy # 导入拷贝模块

class CPU: #CPU类,作为MobilePhone的组件
pass

class MobilePhone: #手机类,包含一个CPU组件
def init(self, cpu):
self.cpu = cpu # 初始化时传入CPU对象

创建原始对象
c = CPU() # 实例化一个CPU对象
m = MobilePhone(c) # 创建包含该CPU的手机对象

print("---- 引用赋值 ----")
m_ref = m # 简单的引用赋值
print("m的内存地址:", id(m)) # 输出原始对象地址
print("m_ref的内存地址:", id(m_ref)) # 与m相同
print("m.cpu的内存地址:", id(m.cpu)) # 组件地址
print("m_ref.cpu的内存地址:", id(m_ref.cpu)) # 组件地址相同

print("\n---- 浅拷贝 ----")
m2 = copy.copy(m) # 执行浅拷贝
print("m的内存地址:", id(m)) # 原始对象不变
print("m2的内存地址:", id(m2)) # 新对象地址不同
print("m.cpu的内存地址:", id(m.cpu)) # 原始组件
print("m2.cpu的内存地址:", id(m2.cpu)) # 组件地址相同(浅拷贝特性)

print("\n---- 深拷贝 ----")
m3 = copy.deepcopy(m) # 执行深拷贝
print("m的内存地址:", id(m)) # 原始对象不变
print("m3的内存地址:", id(m3)) # 新对象地址不同
print("m.cpu的内存地址:", id(m.cpu)) # 原始组件
print("m3.cpu的内存地址:", id(m3.cpu)) # 新组件地址不同(深拷贝特性)

组合

除了继承,“组合”也能实现代码的复用!“组合”核心是“将父类对象作为子类的属性”。
is-a 关系,我们可以使用“继承”。从而实现子类拥有的父类的方法和属性。 is-a 关系指的是类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。
has-a 关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。 has-a 关系指的是这样的关系:手机拥有CPU。 MobilePhone has a CPU

class CPU:
def calculate(self):
print("CPU计算中...")

class Screen:
def show(self):
print("屏幕显示中...")

class MobilePhone:
def init(self, cpu, screen):
self.cpu = cpu
self.screen = screen

创建组件
c = CPU()
s = Screen()

组装手机
m = MobilePhone(c, s)

使用功能
m.cpu.calculate()
m.screen.show()

设计模式_工厂模式实现

工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制。
想象这是一家汽车4S店(工厂)
class CarShop:
@staticmethod
def get_car(money):
if money > 1000000: # 预算充足
return LuxuryCar() # 给你豪车
elif money > 200000: # 预算中等
return FamilyCar() # 给你家用车
else: # 预算有限
return MiniCar() # 给你小车

各种车型(不需要知道具体怎么造车)
class LuxuryCar:
def drive(self):
print("开豪车:轰隆隆~")

class FamilyCar:
def drive(self):
print("开家用车:滴滴~")

class MiniCar:
def drive(self):
print("开小车:突突突...")

你作为顾客(调用者)
if name == "main":
告诉4S店你的预算,直接提车
my_car = CarShop.get_car(300000) # 30万预算
my_car.drive() # 输出:开家用车:滴滴~

设计模式_单例模式实现

单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大的降低开销。
⚠单例模式有多种实现的方式,我们这里推荐重写 new() 的方法。

class 饮水机: # 定义一个饮水机类
_唯一饮水机 = None # 类变量,用来保存唯一的饮水机实例

def __new__(cls):  # 重写__new__方法控制实例创建
    if not cls._唯一饮水机:  # 如果还没有饮水机
        cls._唯一饮水机 = super().__new__(cls)  # 创建一个新的饮水机
        cls._唯一饮水机.水量 = 1000  # 初始化水量为1000ml
    return cls._唯一饮水机  # 返回这个唯一的饮水机

def 接水(self, 毫升):  # 定义接水方法
    if self.水量 >= 毫升:  # 如果水量足够
        self.水量 -= 毫升  # 减少水量
        print(f"接出{毫升}ml水,剩余{self.水量}ml")  # 打印接水信息
    else:  # 如果水量不足
        print("水量不足!")  # 提示水量不足

使用示例

饮水机1 = 饮水机() # 第一次获取饮水机
饮水机1.接水(200) # 从饮水机接200ml水

饮水机2 = 饮水机() # 第二次获取饮水机
饮水机2.接水(300) # 从饮水机接300ml水

print(饮水机1 is 饮水机2) # 检查是否是同一个饮水机,输出True

工厂和单例模式结合

只需要简单的套用即可实现:

饮料工厂(单例模式确保只有一个工厂)

class 饮料工厂:
_唯一工厂 = None # 保存唯一工厂实例

def __new__(cls):  # 控制实例创建
    if not cls._唯一工厂:  # 如果还没有工厂
        cls._唯一工厂 = super().__new__(cls)  # 创建唯一工厂
        cls._唯一工厂.饮料配方 = {  # 初始化配方库
            "可乐": ["糖浆", "碳酸水"],
            "雪碧": ["柠檬酸", "碳酸水"],
            "芬达": ["橙汁", "碳酸水"]
        }
    return cls._唯一工厂  # 返回唯一工厂

def 生产饮料(self, 类型):  # 生产饮料方法
    if 类型 in self.饮料配方:  # 检查是否能生产
        原料 = self.饮料配方[类型]  # 获取原料
        print(f"正在用{原料}生产{类型}")  # 打印生产信息
        return 饮料(类型, 原料)  # 返回饮料对象
    else:  # 没有配方的情况
        print(f"无法生产{类型}")  # 提示无法生产
        return None  # 返回空值

饮料产品类

class 饮料:
def init(self, 名称, 原料): # 初始化方法
self.名称 = 名称 # 设置饮料名称
self.原料 = 原料 # 设置原料列表

def 描述(self):  # 描述方法
    print(f"这是一瓶{self.名称},由{self.原料}制成")  # 打印描述

使用示例

if name == "main":
工厂1 = 饮料工厂() # 第一次获取工厂
工厂2 = 饮料工厂() # 第二次获取工厂

print(工厂1 is 工厂2)  # 检查是否是同一工厂,输出True

可乐 = 工厂1.生产饮料("可乐")  # 生产可乐
雪碧 = 工厂2.生产饮料("雪碧")  # 生产雪碧
未知饮料 = 工厂1.生产饮料("奶茶")  # 尝试生产不存在的饮料

if 可乐:  # 如果生产成功
    可乐.描述()  # 描述可乐
if 雪碧:  # 如果生产成功
    雪碧.描述()  # 描述雪碧

posted on 2025-04-22 22:00  刘晋宇  阅读(43)  评论(0)    收藏  举报

导航