Python_多继承

1.多继承的概念和语法

子类只有一个父类这种情况, 我们把它叫做单继承。

如果一个子类拥有多个父类, 就意味着这个子类拥有所有父类的属性和方法。一句话讲, 一个子类继承所有父类的属性和方法就叫做多继承。

如果我们在开发时希望某一个子类拥有多个父类, 那就可以在子类名后面跟上一对小括号(), 然后把每个父类名放在小括号中间, 并且使用逗号分隔。

在工作中, 如果有两个类A 和 B已经开发完成, 我们希望有一个类既具有A 的特点,又具有B 的特点, 这个时候我们就可以使用多继承, 让这个子类同时继承多个父类。多继承可以让子类对象,同时具有多个父类的属性和方法。

# 让子类 C 继承父类 A和B

class A:
     
     def test(self):
         print("test方法")


class B:

    def demo(self):
        print("demo方法")

class C(A, B):
    # 多继承可以让子类对象,同时具有多个父类的属性和方法
    pass

# 创建子类对象
c = C()

c.test()
c.demo()

运行结果:

成功调用两个父类方法

继承这个特性就是保证在我们的开发中尽量的不要让相同的代码重复的编写, 降低代码的冗余。

2.多继承的使用注意事项

在我们开发时,如果遇到这种情况,如果父类之间存在同名的属性或者方法, 应该尽量避免使用多继承。这种情况会影响到我们代码的阅读。

 演练: 先继承A, 再继承B

# 让子类 C 继承父类 A和B
# class C(A, B): 先继承A, 再继承B   class C(B, A): 先继承B, 再继承B

class A:
     
    def test(self):
        print("A---test方法")

    def demo(self):
        print("A---demo方法")

class B:

    def test(self):
        print("B---test方法")

    def demo(self):
        print("B---demo方法")

class C(A, B):
    # 多继承可以让子类对象,同时具有多个父类的属性和方法
    pass

# 创建子类对象
c = C()

c.test()
c.demo()

 运行结果:

 复制粘贴后出现的报错:

IndentationError: unindent does not match any outer indentation level 

IndentationError: unindent不匹配任何外部缩进级别

实际原因: 复制粘贴后, 看似缩进了,看上去和缩进没有区别, 但实际上没有缩进

详见:CSDN > 收藏 > 报错

演练: 先继承B, 再继承A

# 让子类 C 继承父类 A和B
# class C(A, B): 先继承A, 再继承B   class C(B, A): 先继承B, 再继承B

class A:
     
    def test(self):
        print("A---test方法")

    def demo(self):
        print("A---demo方法")

class B:

    def test(self):
        print("B---test方法")

    def demo(self):
        print("B---demo方法")

class C(B, A):
    # 多继承可以让子类对象,同时具有多个父类的属性和方法
    pass

# 创建子类对象
c = C()

c.test()
c.demo()

运行结果:

3.MRO方法搜索顺序

MRO 可以翻译成 方法解决顺序, 或者 方法搜索顺序。 所谓方法搜索顺序,就是我们让一个对象调用某一个方法时,python 的解释器是按照什么样的顺序在创建这个对象的类以及父类之间搜索方法的, 这就叫做方法搜索顺序。

在python中,针对类有一个内置属性, __mro__, 内置属性应该有两个下划线开头,两个下划线结尾。当我们让一个对象调用某一个方法时, python 的解释器会按照__mro__ 这个属性 输出的顺序来确定一下到底应该执行哪一个类中封装的方法。

代码演练:我们要确定C类对象调用方法的顺序

# 让子类 C 继承父类 A和B
# class C(A, B): 先继承A, 再继承B   class C(B, A): 先继承B, 再继承B

class A:
     
    def test(self):
        print("A---test方法")

    def demo(self):
        print("A---demo方法")

class B:

    def test(self):
        print("B---test方法")

    def demo(self):
        print("B---demo方法")

class C(B, A):
    # 多继承可以让子类对象,同时具有多个父类的属性和方法
    pass

# 创建子类对象
c = C()

c.test()
c.demo()

# 确定C类对象调用方法的顺序
print(C.__mro__)  #再控制台输出了一个元组

输出结果:

我们既然要确定C 类的对象, 就先访问 __mro__ 这个内置属性, print(c.__mro__), 运行一下程序, 控制台输出了一个元组, 当我们让C类创建的对象调用方法时, python 的解释器会首先在C 类中来查找有没有这个方法, 如果有,就会直接执行, 不会向后搜索,如果没有搜索到这个方法, 就会按照元组的顺序从左向右来查找第二类,也就是B类是否提供这个方法,其余同理。当我们让C类的对象调用某一个方法的时候, 首先会在当前类中(也就是C类)来查找这个方法, 找到就执行, 没有找到就按照__mro__ 的顺序从左到右顺序的查找,当找到最后一个基类还没有找到方法, 程序就会报错了。    最后一个是 object 类, 在python 3中, object 这个类是所有类的基类, 只要我们定义了一个类, 这个类最终的基类都是object 这个类, 用大白话来讲, object 这个类是python 3 中所有类的祖宗类。

4.新式类和经典类

python 为所有的对象提供一个object 基类, 在这个基类中封装有一系列的内置属性和方法, 可以使用 dir 这个函数查看到。在python 中,如果我们定义的类是以object 这个类为父类的类, 那么这个类就叫做新式类。如果我们定义的类没有以object 这个类为父类, 那么就叫做经典类, 也叫做旧式类, 旧式类是开发时不推荐使用的。

只输入ipython ,并没有输入3, 直接回车,会打开python 2.x的交互式解释器。

现在使用class 关键字来定义一个A类, 并且让A 类继承自object 这个基类, 然后先使用pass 做个占位, 这样一个空的A类就定义完成了, 现在就使用A类来创建一个 a 的对象, a = A(),然后在使用dir 这个函数来查看一下 a这个对象中都具有哪些属性, dir(a), 回车之后, 会看到很多以两个下划线开头, 两个下划线结尾的内置属性和方法, 这些内置属性和方法,就是object 这个基类提供的。

现在再来使用class 关键字定义一个 B类, 并且不指定任何的父类, 使用pass 做一个占位, 现在就使用B类来创建一个 b 的对象, b = B(),然后在使用dir 这个函数来查看一下 b这个对象中都具有哪些属性, dir(b), 回车之后,我们只能看到两个内置的属性, 如果我们定义一个类, 没有指定object 这个类作为父类, 这个就是旧式类。

新式类创建的对象默认就拥有了父类的内置属性和方法。因为在python 2.x 中,我们定义一个类的时候, 可以指定父类, 也可以不指定父类, 但是由于新式类是我们推荐使用的, 所以如果我们使用python 3.x 的解释器在定义类的时候,如果没有指定父类, 会默认使用object 这个类作为这个类的基类, 意味着在python 3.x 中, 无论是否指定基类, 定义出来的类都是新式类。

先敲一个exit 退出ipython 2.x , 再敲 ipython 3.x ,回车。

现在仍然使用class 关键字定义一个A 类, 同时不给A 类指定任何的父类, 使用pass 做一个占位, 一个空的A 类就定义完成了, 现在就使用A类来创建一个 a 的对象, a = A(),然后在使用dir 这个函数来查看一下 a这个对象中都具有哪些属性, dir(a), 回车之后, 会看到很多以两个下划线开头, 两个下划线结尾的内置属性和方法, 这些内置属性和方法,就是object 这个基类提供的。但是刚刚在定义A 类的时候, 没有指定父类, 因为在python 的解释器中, 如果我们定义类时,没有指定父类, python 解释器会默认使用object 这个基类作为我们定义类的父类, 因此, 在python 3.x 中,我们定义的类都是新式类, 这个就是新式类和经典类在python 2.x 和python 3.x 中的区别。

新式类和经典类在使用多继承时,方法的搜索顺序是有差异的, 所以为了保证编写的代码能够同时在 python 2.x 和python 3.x 中运行, 今后在定义类时, 如果没有父类,我们都主动的指定一下 object 这个基类作为类的父类, 这样就可以保证我们定义出来的类一定都是新式类。如果不主动指定, 那么我们编写的代码一旦在python 2.x下运行, 定义出来的类就是经典类。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值