Python学习 -- 面向对象继承和多态

面向对象–三大特性

  1. 封装 根据职责将 属性方法 封装到一个抽象
  2. 继承 实现代码的重用(复用),实现相同的代码不需要重复的编写
  3. 多态 不同的子类对象调用相同的父类方法,产生不同的执行结果,增加代码灵敏度

面向对象–继承

继承,让类和类之间有上下级联动,为稍后的多态做好准备

class Animal:
    """
    @ Author: EvanZhang
    @ Date: 2025/4/7 14:47
    @ Info: 动物主类
    """
    def __init__(self):
        pass
    def eat(self):
        print("1")
    def sleep(self):
        print("2")
    def play(self):
        print("3")

class Cat(Animal):

class Dog(Animal):

tom = Cat()
tom.play()
spk = Dog()
spk.sleep()

# 结果
3
2

继承的语法

class 父类():
	pass
class 子类(父类名): # 继承,在类的括号中直接引入父类
    pass
  • 子类继承自父类,拥有父类的所有方法和属性,可以直接调用父类中已经封装好的方法,不需要二次开发
  • 子类中可以根据自身的需要,封装属于自己的属性和方法

专业术语

在上面的例子中:

  • Dog 类是 Animal 类的子类,Animal 类是 Dog 类的父类,Dog 类从 Animal 类 继承
  • Dog 类是 Animal 类的派生类,Animal 类是 Dog 类的基类,Dog 类从 Animal 类派生

继承的传承性

如果C类从B类继承,B类又从A类继承,那么C类也拥有A类的属性和方法

子类拥有父类及父类的父类中封装的所有属性和方法
在这里插入图片描述
父类与子类关系
在这里插入图片描述
子类父类内存空间示意

方法重写

  • 当父类的方法实现不能满足子类需求时,可以对方法进行 重写(override)

重写 父类方法有两种情况:

  1. 覆盖 父类的方法

  2. 对父类方法进行扩展

覆盖父类的方法
  • 如果在开发中,父类的方法实现子类的方法实现完全不同
  • 就可以使用 覆盖 的方式,在子类中 重新编写 父类的方法实现

具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现

重写之后,在运行时,只会调用 子类中重写的方法,而不再会调用 父类封装的方法

示例代码:

class Animal:
    
    def __init__(self):
        pass
    def eat(self):
        print("eat")

class Cat(Animal):
    def eat(self):
        print("鱼")
class Rabbit(Animal):
    def eat(self):
        print("草")

tom = Cat()
tom.eat()
mltt = Rabbit()
mltt.eat()
# 结果
鱼
草
对父类方法进行扩展
标准方法

如果在开发中,子类的方法实现中 包含父类的方法实现,即父类原本封装的方法实现子类方法的一部分,就可以使用扩展的方式对父类方法进行扩展

  1. 在子类中 重写 父类的方法
  2. 在需要的位置使用 super().父类方法 来调用父类方法的执行
  3. 代码其他的位置针对子类的需求,编写 子类特有的代码实现

关于 super

  • Pythonsuper 是一个 特殊的类
  • super() 就是使用 super 类创建出来的对象
  • 最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
调用父类方法的另外一种方式(知道)

Python 2.x 时,如果需要调用父类的方法,还可以使用以下方式:

父类名.方法(self)
  • 这种方式,目前在 Python 3.x 还支持这种方式
  • 这种方法 不推荐使用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改

提示

  • 在开发时,父类名super() 两种方式不要混用
  • 如果使用 当前子类名 调用方法,会形成递归调用,出现死循环

子类调用父类的属性

调用父类中的方法或属性

子类可以通过super()来调用父类的方法或属性

class User:
    def __init__(self,name,age):
        self.name = name
        self.age = age
class Studend(User):
    def __init__(self,name,age,id)
    super().__init__(name,age)
    self.id = id    # 调用父类属性
调用自身类的方法或属性

通过 类.方法/变量 来调用

class A:
    a = 1
    __b = 2
    def __init__(self):
        print(A.a,A.__b)    # 通过 类.方法/变量 来调用
        pass

多继承

子类 可以拥有 多个父类,并且具有 所有父类属性方法

class User:
    def add(self):
        print("v1")
class Person:
    def add(self):
        print("v2")
    def add2(self):
        print("v2")
class Student(User,Person): # 多继承,第一个User,第二个Person
    pass

lufei = Student()
lufei.add()
lufei.add()
lufei.add2()
# 结果
v1
v1
v2

当多继承中有某两个父类的方法名相同时,会优先使用子类中第一个继承的父类的方法,包括重写也是

因此,尽量避免在多继承的父类中使用相同的用户名,如果实在避不开,则考虑避免使用多继承,避免产生混淆!

新式类与旧式(经典)类

objectPython 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看

  • 新式类:以 object 为基类的类,推荐使用
  • 经典类:不以 object 为基类的类,不推荐使用
  • Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类
  • Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类

新式类经典类 在多继承时 —— 会影响到方法的搜索顺序

为了保证编写的代码能够同时在 Python 2.xPython 3.x 运行!
今后在定义类时,如果没有父类,建议统一继承自 object

class 类名(object):
    pass

继承中子类父类初始化问题

在子类没有提供init初始化方法时,子类在初始化的过程中时会默认先初始化父类

如果程序员在子类手动提供了init的初始化方法,那么在执行过程中Python解释器不会去执行父类的init,此时如果要使用父类的初始化属性则会报错

​ 解决方法:在子类初始化时手动使用super().__init__调用父类初始化方法

虽然在子类手动提供init会使父类的init不执行,但仍会执行父类的new方法去开辟内存空间

抽象类

抽象类引入

主旨思想:在后续的开发过程中需要严格统一开发标准,标准化开发,约束子类开发,强制所有子类重写父类的抽象方法

# 场景  支付:微信、支付宝、云闪付、银行...
# 统一支付接口

class WeChat(object):
    """
    @Author: EvanZhang
    @Date: 2025/4/8 11:09
    @Info: 微信支付接口
    """
    def __init__(self):
        pass
    def pay(self,money):
        print("wechat pay %.2f"%money)
class Ali(object):
    """
    @Author: EvanZhang
    @Date: 2025/4/8 11:09
    @Info: 阿里支付接口
    """
    def __init__(self):
        pass
    def pay(self,money):
        print("ali pay %.2f"%money)
# wechat = WeChat()
# wechat.pay(100)
# ali = Ali()
# ali.pay(200)

# 对代码进行改造:统一支付
def pay(obj,money):
    obj.pay(money)

wechat = WeChat()
ali = Ali()
pay(wechat,150)
pay(ali,200)

上述代码问题:虽然开发了pay()统一支付方式,但是程序员(用户)仍然可以使用自己的支付方式(24-27行代码)来执行

因此接下来需要限定用户必须通过指定方式来执行代码,那么就需要用到抽象类技术

定义抽象类

第一步,引入抽象类模块

from abc import abstractmethod,ABCMeta  #引入抽象方法和抽象类

第二步,在需要成为抽象类的类名后面添加抽象类模块

class BaseDao(metaclass=ABCMeta):

第三步,在抽象类方法前加入@abstractmethod注解

    @abstractmethod
    def addUser(self):
        pass

第四步,子类继承抽象类,强制实现抽象类中的方法

# 场景:数据库的增删改查
class UserDao(BaseDao):
    def addUser(self):
        print("对接数据库做增加操作")
        pass
    def updateUser(self):
        print("对接数据库做更新操作")
        pass
    def delUser(self):
        print("对接数据库做删除操作")
        pass
    def getUser(self):
        print("对接数据库做获取操作")
        pass

面向对象–多态

定义

一种对象存在多种形态,称为多态,即 不同的子类对象调用相同的父类方法,产生不同的执行结果

  • 增加代码灵敏度
  • 继承重写父类方法为前提
  • 是调用方法的技巧不影响类的内部设计

案例

地上有一群鸟(20只),一声枪响,有的飞起来了,有的跑起来了…

class Bird:
    def run(self):
        print("飞或者跑....")
class FlyBird(Bird):
    def run(self):
        print("飞起来了....")
class RunBird(Bird):
    def run(self):
        print("跑起来了.........")

class Person:
    def play(self,bird):
        bird.run()

import random
lufei = Person()
for i in range(20):
    num = random.randint(0,1)
    if num == 0:
        bird = FlyBird()
    elif num == 1:
        bird = RunBird()
    lufei.play(bird)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值