Python 多继承中的一个诡异现象 既是 Father又是grandfather

目录

我们知道,在面向对象编程里面, 继承 是一个很重要的概念。子类可以使用父类的方法和属性。

例如下面这段代码:

class Father:
    def __init__(self):
        self.address = '上海'

    def say(self):
        print('我是爸爸')

class Son(Father):
    def __init__(self):
        super().__init__()

    def say(self):
        print('我是儿子')

son = Son()
print(son.address)

运行效果如下图所示:

从图中可以看到,子类并没有 self.address 这个属性,但是当我们直接打印的时候,并不会报错,它会自动使用父类的 address 属性。

显然,如果一个属性,子类也没有,父类也没有,那肯定会报错,如下图所示:

我们也知道,Python 是支持多继承的,一个子类可以有多个父类。那么,大家请看下面这段代码:

class GrandFather:
    def __init__(self):
        self.address = '上海'

    def say(self):
        print('我是爸爸')

class Father:
    def __init__(self):
        self.age = 100

    def where(self):
        print('我现在住在:', self.address)

class Son(GrandFather, Father):
    def __init__(self):
        super().__init__()

    def say(self):
        print('我是儿子')

son = Son()
son.where()

运行效果如下图所示:

大家仔细观察,会发现这段代码有点奇怪。我调用的是 son.where() 方法,由于 Son 类没有这个方法,于是它会去它的两个父类里面找。于是在 Father 这个父类里面找到了。于是执行 Father 里面的 where() 方法,目前为止没有问题。

但接下来就不对了, .where() 方法里面,调用了 self.address 属性。可问题是 Father 这个类它并没有 .address 属性啊!而且 Father 也没有父类,那么这个 .address 属性是从哪里来的?

难道说,在开发者不知道的隐秘的角落里面, GrandFather 类悄悄成为了 Father 的父类?这样一来, GrandFather 岂不是又是 C 的父类,又是 C 的父类的父类? GrandFather 既是爸爸又是爷爷?

实际上,并不存在这么混乱的关系。要解释这个现象,我们就要从 self 这个东西说起。

我们知道,类的属性都是以 self 开头,方法的第一个参数也是 self 。那么这个  self 到底是什么东西?我们用一段小代码来看看它是什么东西:

class A:
    def get_self(self):
        return self

test = A()
what_is_self = test.get_self()

test is what_is_self

运行效果如下图所示:

从图里面可以看到, self 实际上就是这个类的实例。我们再来看有继承的情况:

class A:
    def get_self(self):
        return self

class B(A):
    def __init__(self):
        ...

test = B()
what_is_self = test.get_self()

print(what_is_self)

从图中可以看到,虽然我在 A 类的 .get_self() 方法中返回了 self ,但这个 self 实际上是 B 类的实例。因为我自始至终就只初始化了 B 类,并没有初始化 A 类。A 虽然是 B 类的父类。但父类的  self 都会变成子类的实例。

明白这一点以后,前面的问题就很好解释了,我们多打印一些信息:

大家注意画红线的地方, self 始终都是 Son 类的实例。所以,一开始初始化 .address 的时候,就是初始化的 Son 的实例的 .address 属性。后面在 .where 里面调用 .address 的时候,也是读取的 Son 的实例的 .address 属性。所以,并不存在 Father 类去读 GrandFather 类的情况。自始至终,都是 Son 类的实例在进行各种操作。

所以,在这个例子里面,当使用了继承以后,所有父类的属性和方法,子类如果有相同的名字,那么以子类的为准。如果子类没有定义,那么父类的属性和方法,其实都会跑到子类里面去。 所有看起来是父类进行的操作,其实都是子类在进行 。上面的代码,甚至可以近似等价于:

由于 say 方法在子类中有了定义,所以子类覆盖父类。以子类的 say 方法为准。 where address 由于子类没有定义,所以 Father 类的 where 方法和 GrandFather 里面的 address 属性,都会直接 跑 到子类里面。

到此这篇关于Python 多继承中的一个诡异现象 既是 Father又是grandfather的文章就介绍到这了,更多相关Python 多继承中的一个诡异现象 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python面向对象程序设计多继承和多态用法示例

    本文实例讲述了Python面向对象程序设计多继承和多态用法.分享给大家供大家参考,具体如下: 多继承 就是一个子类继承多个父类: 多继承的例子,如下: # -*- coding:utf-8 -*- #! python3 class Base(object): def test(self): print("------base") class A(Base): def test1(self): print("-----test1") class B(Base): de

  • Python多继承原理与用法示例

    本文实例讲述了Python多继承原理与用法.分享给大家供大家参考,具体如下: python中使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承,也叫菱形继承问题)等 MRO MRO即method resolution order,用于判断子类调用的属性来自于哪个父类.在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类 从图中可以看出,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索 C3算法

  • 在python里面运用多继承方法详解

    如何在PYTHON里面运用多继承 class Father: def hobby(self): print("love to play video game.") class Mother: def cook(self): print("love to cook anything.") #比如说有两个类,如果想要一个子类同时继承这两个类,应该怎么操作呢. class Father: def hobby(self): print("love to play

  • Python多继承以及MRO顺序的使用

    多继承以及MRO顺序 1. 单独调用父类的方法 # coding=utf-8 print("******多继承使用类名.__init__ 发生的状态******") class Parent(object): def __init__(self, name): print('parent的init开始被调用') self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name,

  • python支持多继承吗

    大部分面向对象的编程语言(除了C++)都只支持单继承,而不支持多继承,为什么呢?因为多继承不仅增加编程复杂度,而且容易导致莫名其妙的错误. Python虽然语法上支持多继承,但是却不推荐使用多继承,而是推荐使用单继承,这样可以保证编程思路更清晰,也可以避免不必要的麻烦. 当以一个子类有多个直接父类时,该子类会继承得到所有父类的方法,但是如果其中有多个父类包含同名方法会发生什么?此时排在前面的父类中的方法会"遮蔽"后面父类中的方法. 栗子如下: #coding=utf-8 class I

  • Python多继承顺序实例分析

    本文实例讲述了Python多继承顺序.分享给大家供大家参考,具体如下: 示例1: #-*- coding:utf-8 -*- #!python2 class A(object): def caller(self): print 'A caller' self.called() def called(self): print 'A called' class B(object): def called(self): print 'B called' class C(B,A): pass if __

  • Python面向对象程序设计之继承与多继承用法分析

    本文实例讲述了Python面向对象程序设计之继承与多继承.分享给大家供大家参考,具体如下: 1. 继承 在C++和Java中,使用继承时,子类的构造函数会自动调用父类的构造函数,但在Python中,子类必须显式的在__init__()函数中再次调用父类中的__init__()函数.如下例: class Employee(object): def __init__(self, name, salary = 0): self.name = name self.salary = salary def

  • python多继承(钻石继承)问题和解决方法简单示例

    本文实例讲述了python多继承(钻石继承)问题和解决方法.分享给大家供大家参考,具体如下: 在菱形多继承中,如果用父类.__init__()来调用父类的初始化方法,最上层会执行两次,所以遇到这种情况,python中用super.__init__()来解决这个问题. # -*- coding:utf-8 -*- #! python3 class Grand_father(object): def __init__(self): print('爷爷') class Father_left(Gran

  • 详细总结Python类的多继承知识

    一.Python不同版本的类 Python2.2之前是没有共同的祖先的,之后引入Object类,它是所有类的共同祖先类Object Python2中为了兼容,分为古典类(旧式类)和新式类 Python3中全部都是新式类 新式类都是继承自Object的,新式类可以使用super #古典类在python2.x中运行 class A: pass print(dir(A)) # ['__doc__', '__module__'] print(A.__bases__) # () a = A() print

  • Python中的单继承与多继承实例分析

    本文实例讲述了Python中的单继承与多继承.分享给大家供大家参考,具体如下: 单继承 一.介绍 Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义.派生类的定义如下所示: class DerivedClassName(BaseClassName1): <statement-1> . . . <statement-N> 需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类

随机推荐