Python 多继承中的一个诡异现象 既是 Father又是grandfather
作者:itskingname 发布时间:2023-02-06 10:24:34
我们知道,在面向对象编程里面, 继承 是一个很重要的概念。子类可以使用父类的方法和属性。
例如下面这段代码:
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
属性,都会直接 跑 到子类里面。
来源:https://www.tuicool.com/articles/iIZRjuM


猜你喜欢
- MySQL 8.0.29 详细安装(windows zip版),供大家参考,具体内容如下1 官网官网地址:MySQL2 下载下载地址:MyS
- 先上效果,视频敬上:字符舞:代码舞源代码:video_2_code_video.pyimport argparseimport osimpo
- Flask提供了多种身份认证方式,其中基于Token的身份认证是其中一种常用方式。基于Token的身份认证通常是在用户登录之后,为用户生成一
- 如果你是pytorch的用户,可能你会很熟悉pytorch生态圈中专门预处理图像数据集的torchvision库。从torchtext这个名
- python可以编写win程序。win程序的格式是exe,下面我们就来看一下使用python编写exe程序的方法。编写好python程序后p
- 1. 进入SSMS点击展开sqlserver代理,右键点击“作业”,然后选择新建作业。2. 填写名称
- 在我们做搜索的时候经常要用到模糊查询 (注:其中name1,name2,name3,name4为数据库字段) 1.方法 sql="
- import numpy as npimport sysdef conv_(img, conv_filter): filter_
- 在任何语言中,都会规定某些对象(属性、方法、函数、类等)只能够在某个范围内访问,出了这个范围就不能访问了。这是“公”、“私”之分。此外,还会
- 如何使用快捷键按出代码提示框更新win10,发现可以改取消ctrl + space快捷键的占用了!!!我们在平时写代码的时候难免会出现敲错字
- 继上一篇计算checksum校验和,本章通过socket套接字,struct字节打包成二进制,select返回套接字的文件描述符的结合,实现
- 本文实例为大家分享了TP3.2批量上传文件或图片的具体代码,并解决了同名冲突问题,供大家参考,具体内容如下1、html<form ac
- python的版本及依赖的库的安装#版本python 3.7.1pip install pywin32==224pip install nu
- 目录查找和修复数据表冲突更新索引统计查找和修复数据表冲突数据表最糟糕的事情就是发生冲突。使用MyISAM存储引擎时,通常因为崩溃导致冲突。然
- 两张表,A表中的记录B表中不一定有。左连接:关注左边,右边没有就为空。右连接:关注右边,左边没有就为空。内连接:返回交集例如:student
- 题目请设计并实现一款主机端口扫描程序。程序根据用户输入的域名或IP地址,可以查询该主机的开放的端口号。 例如:并有一定的异常处理参考code
- 前言:图像处理是常用的技术,python 拥有丰富的第三方扩展库,Pillow 是 Python3 最常用的图像处理库,目前最高版本5.2.
- 工具python3.7PycharmExcelpython-docx生成Word案例创建一个demo.doc文档,代码如下:from doc
- Math.random()Math.random()是JavaScript默认提供的生成随机数的方法。该方法返回一个0到1之间的浮点数,其值
- mergemerge 函数通过一个或多个键将数据集的行连接起来。场景:针对同一个主键存在的两张包含不同特征的表,通过主键的链接,将两张表进行