python 基础系列(五) — Python中的继承

本文深入探讨Python中的继承和多态概念,包括单继承、多继承、方法重写、多态的应用及其实现机制。通过示例代码,详细解析继承的语法、优点和注意事项,以及如何使用super()和类名调用父类方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python 基础系列(五) — Python中的继承



python基础系列索引

python 基础系列(一) — Python介绍

python 基础系列(二) — Python基本语法

python 基础系列(三) — Python中的变量进阶

python 基础系列(四) — Python中的面向对象

python 基础系列(五) — Python中的继承

python 基础系列(六) — Python的异常及其处理

python 基础系列(七) — Python中的模块

python 基础系列(八) — Python中的文件操作

python 基础系列(九) — Python中的vi – 终端中的编辑器

python 基础系列(十) — Windows CMD命令大全

python 基础系列(十一) — 使用PyCharm远程调试树莓派python代码 — Windows CMD命令大全


如果你对python感兴趣,不妨看一下我的其他文章


  • 继承的分类

    • 单继承
    • 多继承

面向对象的三大特性

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

继承的语法

class 类名(父类名):
	pass

代码示例

class Animal:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def sleep(self):
        print("睡觉")


class Dog(Animal):
    def bark(self):
        print("汪汪叫")


class Xiaotianquan(Dog):
    def fly(self):
        print("我是哮天犬,我会飞")


xiaotianquan = Xiaotianquan()
xiaotianquan.eat()
xiaotianquan.drink()
xiaotianquan.sleep()
xiaotianquan.bark()
xiaotianquan.fly()

运行结果

吃
喝
睡觉
汪汪叫
我是哮天犬,我会飞

继承中的方法重写

继承的优点

  • 子类拥有父类全部的方法和属性
  • 子类继承自父类,可以直接享用父类的方法,不用再次开发

重写父类方法的两种情况

  • 覆盖父类的方法
  • 对父类的方法进行扩展

覆盖父类的方法:

代码示例:

class Animal:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def sleep(self):
        print("睡觉")


class Dog(Animal):
    def bark(self):
        print("汪汪叫")


class Xiaotianquan(Dog):
    def fly(self):
        print("我是哮天犬,我会飞")
    def bark(self):
        print("和人一样的叫...")


xiaotianquan = Xiaotianquan()
xiaotianquan.eat()
xiaotianquan.drink()
xiaotianquan.sleep()
xiaotianquan.bark()
xiaotianquan.fly()

执行结果

吃
喝
睡觉
和人一样的叫...
我是哮天犬,我会飞
  • 扩展父类的方法,使用 super() 方法调用父类方法,当然我们也可以使用 父类名.方法名(self)的形式进行调用,当然,self是必须传递的

    class Animal:
    def eat(self):
    print(“吃”)

      def drink(self):
          print("喝")
    
      def sleep(self):
          print("睡觉")
    

    class Dog(Animal):
    def bark(self):
    print(“汪汪叫”)

    class Xiaotianquan(Dog):
    def fly(self):
    print(“我是哮天犬,我会飞”)
    def bark(self):
    print(“和人一样的叫…”)
    # 使用 super() 方法调用父类方法
    super()
    print(“哮天犬的叫声”)

    xiaotianquan = Xiaotianquan()
    xiaotianquan.eat()
    xiaotianquan.drink()
    xiaotianquan.sleep()
    xiaotianquan.bark()
    xiaotianquan.fly()

运行结果

吃
喝
睡觉
和人一样的叫...
哮天犬的叫声
我是哮天犬,我会飞

使用父类名的方式调用

示例代码

class Animal:
    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def sleep(self):
        print("睡觉")


class Dog(Animal):
    def bark(self):
        print("汪汪叫")


class Xiaotianquan(Dog):
    def fly(self):
        print("我是哮天犬,我会飞")
    def bark(self):
        print("和人一样的叫...")
        #  `父类名.方法名(self)`的方式调用父类方法
        Dog.bark(self)
        print("哮天犬的叫声")


xiaotianquan = Xiaotianquan()
xiaotianquan.eat()
xiaotianquan.drink()
xiaotianquan.sleep()
xiaotianquan.bark()
xiaotianquan.fly()

运行结果:

吃
喝
睡觉
和人一样的叫...
汪汪叫
哮天犬的叫声
我是哮天犬,我会飞

注意:子类名调用会出现死循环

父类的私有属性和私有方法不可以被子类访问

代码示例

class Animal:
    def eat(self):
        self.__food = "实物"
        print("吃")

    def __drink(self):
        print("喝")

    def sleep(self):
        print("睡觉")


class Xiaotianquan(Animal):
    def fly(self):
        print("我是哮天犬,我会飞")
        print("获取事物%s" % self.__food)
        self.__drink()


xiaotianquan = Xiaotianquan()
xiaotianquan.fly()

执行结果

Traceback (most recent call last):
File "E:/学习和总结/groovyStudy/python实战代码/newcode/venv/Include/soldiers_raided.py", line 88, in <module>
    xiaotianquan.fly()
File "E:/学习和总结/groovyStudy/python实战代码/newcode/venv/Include/soldiers_raided.py", line 83, in fly
    print("获取事物%s" % self.__food)
AttributeError: 'Xiaotianquan' object has no attribute '_Xiaotianquan__food'

python中的多继承

  • 子类可以拥有刀哥父类,并且具有所有子类的属性和方法
  • 如孩子可以继承爸爸和妈妈的所有属性

多继承语法

继承的语法

class 类名(父类名1,父类名2):
	pass

多继承,注意避免父类出现同名属性或者同命方法

如果开发中父类存在同名的属性或者是方法,应当避免使用多继承,如果使用可,法法和属性的调用会直接引用依赖前面的对象的属性和方法

代码演示

class A:
    def __init__(self):
        self.name="A"
    def test(self):
        print(self.name)
        print("A 的 test方法")
class B:
    def __init__(self):
        self.name = "B"

    def test(self):
        print(self.name)
        print("B 的 test方法")


class C (B,A):
    pass

c=C()
print(c.name)
c.test()

执行结果

B
B
B 的 test方法

python 中MRO – 方法搜索顺序

查看类中方法的的调用顺序

类名.__mro__

运行结果

(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

从上面的结果可以看出 ,优先从当前类C中查找属性或者方法;如果没有找到就会从类B中查找,如果还是没有找到,如果,没有找到就会从类A中查找

面向对象中的多态

  • 多态: 不同的子类对象调用相同的父类方法,产生不同的执行结果
    • 多态 可以增加代码的灵活性
    • 继承重写父类的方法 为前提
    • 是调用方法的技巧,不会影响到类的内部设计

重写父类的方法,可以使相同的方法得到不同的执行结果

代码示例

class Dog:
    def __init__(self, name):
        self.name = name

    def game(self):
        print("%s 蹦蹦跳跳的玩耍..." % self.name)


class XiaoTianQuan(Dog):
    def game(self):
        print("%s 飞到天上去玩耍..." % self.name)


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

    def game_with_dog(self, dog):
        print("%s 和 %s 快乐的玩耍" % (self.name, dog.name))
        dog.game()


# 创建一个狗对象
wangcai = Dog("旺财")
xiaotianquan=XiaoTianQuan("小权")

# 创建一个人对象
xiaoming = Person("小明")

# 人和狗一起玩耍
xiaoming.game_with_dog(wangcai)
xiaoming.game_with_dog(xiaotianquan)

运行结果

小明 和 旺财 快乐的玩耍
旺财 蹦蹦跳跳的玩耍...
小明 和 小权 快乐的玩耍
小权 飞到天上去玩耍...

实例

使用类模板创建出来的对象叫做示例

###类属性和实例属性 ###

  • 类属性(类似java的类的静态成员变量),就是给类对象中定义的属性
  • 通常用来记录 与这个类相关 的特征
  • 类属性 不会用于记录具体对象的特征(换句话说,与具体的一个对象没有关系,和类有关系)

类属性的访问仅可以使用 类名.变量名,无论是在类的内部还是在其他任意的位置,均可以使用上面的方式进行访问

代码示例

class Tool:
    # 使用赋值与定义类属性,记录创建工具对象的总数
    count = 0

    def __init__(self, name):
        self.name = name
        # 每次创建对象针对类属性做一个加一的操作
        Tool.count += 1
        print("Tool.count = %s"% Tool.count)


# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("锄头")
tool3 = Tool("剪刀")

运行结果

Tool.count = 1
Tool.count = 2
Tool.count = 3

python中属性的获取机制

  • 在python中 属性的获取 存在一个 向上的查找机制
  • 因此访问类属性存在两种方式
    • 1.类名.属性名
    • 2.对象名.属性名(不推荐,如果存在对象属性名和类属性名称相同,会优先访问对象的属性名称)

注意

  • 如果使用 对象.类属性 = 值 赋值只会给对象添加一个属性,而不会影响到类属性的值

优先级 方法属性 < 对象属性 < 类属性

使用对象.类属性赋值会出现错误,解释器会优先对对象的属性赋值

class Tool:
    # 使用赋值与定义类属性,记录创建工具对象的总数
    count = 0

    def __init__(self, name):
        self.name = name
        # 每次创建对象针对类属性做一个加一的操作
        Tool.count += 1
        print("Tool.count = %s" % Tool.count)


# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("锄头")
tool3 = Tool("剪刀")

print("使用对象访问类属性 : count = %s" % tool1.count)
tool1.count = 99
print("修改后访问类属性的值 : count = %s" % Tool.count)

运行结果

Tool.count = 1
Tool.count = 2
Tool.count = 3
使用对象访问类属性 : count = 3
修改后访问类属性的值 : count = 3

类方法和静态方法

  • 类属性 就是针对 类对象 定义的属性

    • 使用赋值语句 在 class 关键字下方可以定义类属性
    • 类属性用于记录 与这个类相关 的特征
  • 类方法 就是针对类对象定义的方法

    • 类方法 内部可以直接访问 类属性 或者调用 其他的类方法(类比java静态方法)

基本语法

@classmethod
def method(cls):
    pass	
  • 类方法需要用 @classmethod 来标识,告诉解释器这是一个类方法

  • 类方法的第一个参数 应该是一个 cls

    • 有那个类调用的方法,方法内的 cls 那个类的引用
    • 这个 参数和 实例方法 的第一个参数 self 类似
    • 当然 类方法的参数使用其他变量名称也可以,不过习惯上使用 cls
  • 通过类名调用类方法时,无需传入 cls,那个类调用 cls 就会指向那个类

  • 在方法的内部

    • 可以通过 cls ,访问类的属性
    • 也可以通过 cls,调用其他的类方法

代码示例

class Tool:
    # 使用赋值与定义类属性,记录创建工具对象的总数
    count = 0

    def __init__(self, name):
        self.name = name
        # 每次创建对象针对类属性做一个加一的操作
        Tool.count += 1

    @classmethod
    def show_tool_count(cls):
        print("Tool.count = %s" % cls.count)


# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("锄头")
tool3 = Tool("剪刀")
Tool.show_tool_count()

运行结果

Tool.count = 3

什么时候使用静态方法

在开发中以下两种情况通常将方法定义为静态方法

  • 既不需要访问 示例属性 或调用 实例方法

  • 也 不需要访问 类属性 或调用 类方法

  • 这个时候,可以把这个方法封装成一个 静态方法

语法如下

@staticmethod
def 静态方法名():
    pass
  • 静态方法需要使用 @staticmethod 来标识,告诉编译器这是个静态方法
  • 通过 类名.静态方法名 调用静态方法

代码示例

class Dog:
    @staticmethod
    def show_msg():
        print("这是一个小狗...")

Dog.show_msg()

运行结果

这是一个小狗...

小游戏案例

代码示例

class Game:
    # 记录全场最高成绩
    top_score = 0

    def __init__(self, u_nme):
        self.u_name = u_nme

    @staticmethod
    def show_help():
        print("帮助信息。,让植物进入大门")

    @classmethod
    def show_top_score(cls):
        print("您当前的最高成绩为 %.2f" % cls.top_score)

    def start_game(self):
        print("%s 开始游戏啦!"% self.u_name)


# 1.查看帮助信息
Game.show_help()
# 2.查看历史最高分
Game.show_top_score()
# 3.开始游戏
xiaoming = Game("小明")
xiaoming.start_game()

运行结果

帮助信息。,让植物进入大门
您当前的最高成绩为 0.00
小明 开始游戏啦!

总结 – 方法的类型如何选择:

  • 1.示例方法 – 方法内部需要访问实例属性
    • 内部可以使用 示例名.属性名 方式访问属性
  • 2.类方法 – 方法内部只需要访问类属性
  • 3.静态方法 – 方法内部不需要访问实例属性和类属性

单例设计模式

  • 目的 ,让类创建的对象,在系统中只有唯一的一个实例
  • 每次执行 类名() 返回的对象,内存地址是相同的

复习前面几章我们知道,

对象创建过程,解释器底层实际上做了两件事情

  • 调用 __new__ 为需要创建的对象分配内存地址

  • 调用类的 __init__ 方法,为对象赋初值

  • __new__ 方法是由 Object 基类提供的内置静态方法,主要作用有两个:

    • 在内存中为对象分配内存空间
    • 返回对象的引用
  • python的解释器获得对象的引用后,将引用作为第一个参数,传递给 __init__ 方法

重写 ___new__ 方法的代码非常固定

  • 重写 ___new__ 方法一定要 return super().__new__(cls)
  • 否则python解释器得不到分配了内存的对象的引用,就不会调用对象的初始化方法
  • 注意: ___new__ 是一个静态方法。在调用时需主动传递 cls参数

示例代码

class Game:
    # 记录全场最高成绩
    top_score = 0

    def __new__(cls, *args, **kwargs):
        print("为对象分配内存空间")
		# 没有按照要求返回将会得不到对象地址的引用
        return super().__new__(cls)

    def __init__(self, u_nme):
        self.u_name = u_nme

    @staticmethod
    def show_help():
        print("帮助信息。,让植物进入大门")

    @classmethod
    def show_top_score(cls):
        print("您当前的最高成绩为 %.2f" % cls.top_score)

    def start_game(self):
        print("%s 开始游戏啦!" % self.u_name)


# 1.查看帮助信息
Game.show_help()
# 2.查看历史最高分
Game.show_top_score()
# 3.开始游戏
xiaoming = Game("小明")
xiaoming.start_game()

运行结果

帮助信息。,让植物进入大门
您当前的最高成绩为 0.00
为对象分配内存空间
小明 开始游戏啦!

单例模式的使用

示例代码

class MusicPlayer:
    instance =None

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance=super().__new__(cls)
        return cls.instance



print(MusicPlayer())
print(MusicPlayer())

运行结果

<__main__.MusicPlayer object at 0x00000227022E7E80>
<__main__.MusicPlayer object at 0x00000227022E7E80>

解决单例中,初始化多次的问题

在类属性中增加一个 init_flag 变量作为初始化的标识,初始化成功后将这个标识置为true,后续不再初始化

代码示例

class MusicPlayer:
instance =None
init_flag=False


def __init__(self):
    if MusicPlayer.init_flag :
        return
    # 执行初始化代码
    print("这里是执行的一撮初始化代码")
    # 将标识位置为True
    MusicPlayer.init_flag=True

def __new__(cls, *args, **kwargs):
    if cls.instance is None:
        cls.instance=super().__new__(cls)
    return cls.instance



print(MusicPlayer())
print(MusicPlayer())

运行结果

这里是执行的一撮初始化代码
<__main__.MusicPlayer object at 0x00000172BE0E7E80>
<__main__.MusicPlayer object at 0x00000172BE0E7E80>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值