def __init__(self)是什么意思_子类必须调用 super().__init__() 吗?
我新开了专栏 《恍然大明白》,如果关注 Python 底层实现,请移步
恍然大明白www.zhihu.com
今天遇到一个有意思的问题,小组一位小哥在开发中,遇到了传说中的 “祖传代码”,有一个数据库的封装类 DBM 没有将数据库配置信息暴露到参数中,而是在 __init__ 方法中硬编码。临时新增的需求需要使用不同的数据库,小兄弟很诚实的将整个类实现 COPY 了一份,然后修改了 _init 方法中的数据库配置。
其实解决这个问题有很多方法,比如:
- 这个类的初始化参数进行调整,暴露初始化参数,并为止设置默认值;
- 将一些公用方法抽象到一个更高的父类,DBM 和其他实现继承该父类等等。
当然也可以直接继承祖传的 DBM,重新实现 init 方法,使用新的数据库配置。在子类的 init 方法中主动调用父类的 init 方法,再实现子类的初始化,似乎是一种稳妥的做法,但是调用父类的 init 方法是必须的吗?
一个简单的例子: (所有代码都在 Python3 下运行)
#!/usr/bin/python
Base 中有 1 个属性 name 和 say 方法,假设在子类 Child 中新增属性 color:
class Child(Base):def __init__(self, color):super().__init__()self.color = color# 简单测试父类
base = Base("Lisa")
print(base.name)
base.say()# 子类
child = Child("blue")
try:print(child.name)print(child.color)
except Exception as e:print(e)
child.say()
输出:
Lisa
<class '__main__.Base'> said: Hello!
Lucy
blue
<class '__main__.Child'> said: Hello!
可以看到 Child 继承了所需的 say 方法,相比 Base 新增了 color 属性。但是如果 Child 已经不再需要 name,可以不执行 supper().init() 吗?如果将其注释掉:
# super().__init__()
再尝试运行输出如下:
Lisa
<class '__main__.Base'> said: Hello!
'Child' object has no attribute 'name'
<class '__main__.Child'> said: Hello!
Child 依然继承了 say 方法,但是由于没有调用父类的 init 方法,所以 name 属性就没有被创建,子类中也就不存在这个属性。
所以小哥只需要用一个子类继承 “祖传代码” 中的 DBM 类,并且直接在子类的 init 按照自己的需要初始化即可,无需调用父类的 init 方法。
原因
Python 与 Java、C++ 不同,继承不依赖子类执行父类的 init 方法,init 方法主要完成的是对象的一些初始化工作,真正的对象创建工作是在 new 方法中实现。当子类对象创建完成,Object 在 Python 底层结构都是相同的,在某种程度上它非常像一个字典。只需要对代码稍作修改,在 init 中观察各类实例被 new 之后都包含什么:
#!/usr/bin/python
class Base:def __init__(self, name = "Lucy"):print(f"befor __init__, {self.__class__}:")print(dir(self))self.name = nameprint(f"after __init__, {self.__class__}:")print(dir(self))def say(self):print(f"{self.__class__} said: Hello!")class Child(Base):def __init__(self, color):print(f"befor __init__, {self.__class__}:")print(dir(self))# super().__init__()self.color = colorprint(f"after __init__, {self.__class__}:")print(dir(self))base = Base("Lisa")
print(base.name)
base.say()child = Child("blue")
try:print(child.name)print(child.color)
except Exception as e:print(e)
child.say()
输出太长,我只贴出 Child 的输出:
befor __init__, <class '__main__.Child'>:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'say']
after __init__, <class '__main__.Child'>:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'color', 'say']
显然,在进入 ini 之前,也就是 new 之后,self 中已经包含了大量属性,多数都是内置属性,比较意外的是出现在 __init__ 方法之后的 say 方法反而已经被添加进去了,这是因为 Python 解释类定义的时候,已经知道 Child 继承了 Base 中的 say 方法。另一方面,类的自定义属性都是在稍晚触发 init 才被添加到实例的属性字典中。
如此一来,如果父类 init 方法中的工作不再需要,当然可以不调用。
关注我,了解程序员的烧脑日常,还有开源 Python 教程。
def __init__(self)是什么意思_子类必须调用 super().__init__() 吗?相关推荐
- qt 子类调用父类的函数_子类中调用父类的方法
父类名 . __init__(self, ...) 可以将父类中的init中的属性重复调用,减少代码的重复 class Vehicle: def __init__(self, name, speed, ...
- python父类方法的装饰器_Python使用装饰器自动调用父类__init__
众所周知,Python中class的构造函数实际是__new__(),但是如果我们执行p1=Point()的时候,不仅会调用Point的__new__方法,而且会调用Point的__init__方法. ...
- Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)
Python 在子类中调用父类方法详解(单继承.多层继承.多重继承) by:授客 QQ:1033553122 测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...
- 什么是python中子类父类_零基础入门:python中子类继承父类的__init__方法实例
前言: 今天为大家带来的内容是零基础入门:python中子类继承父类的__init__方法实例!具有不错的参考意义,希望在此能够帮助到各位!(喜欢的话记得点赞转发关注不迷路哦) 使用Python写过面 ...
- python中的继承的初始化_python中子类继承父类的__init__方法实例
前言 使用Python写过面向对象的代码的同学,可能对__init__方法已经非常熟悉了,__init__方法在类的一个对象被建立时,马上运行.这个方法可以用来对你的对象做一些你希望的 初始化 . 注 ...
- qt 子类调用父类的函数_子类调用父类方法
当有相同的属性或者方法是this子类表示调用自己的属性或者方法, super调用父类的属性或者方法. 当子类调用的属性方法在子类中不存在时,那么this和super都是调用父类的属性或者方法 1.方式 ...
- 根据父类id查询所有的父级_父类子类抽象类,super final 重写方法,搞懂继承中复杂的知识点...
继承 继承(Inheritance)可以实现类之间共享属性和方法,是面向对象编程的另一个特性 使用继承可以最大限度地实现代码复用. 定义:继承就是在已有类的基础上构建新的类,一个类继承已有类后,可以对 ...
- idea实现抽象类的所有抽象方法_父类子类抽象类,super final 重写方法,搞懂继承中复杂的知识点
继承 继承(Inheritance)可以实现类之间共享属性和方法,是面向对象编程的另一个特性 使用继承可以最大限度地实现代码复用. 定义:继承就是在已有类的基础上构建新的类,一个类继承已有类后,可以对 ...
- java子类可以修改父类成员吗_子类重写父类成员方法
最近在学习到Java的继承和多态时遇到了这样的一个问题:关于继承链中子类对父类的私有方法是否可以覆盖的问题,在此记录一下自己对这个问题解决以后的一些心得. 首先要明确:子类是不能够覆盖(重写)父类的私 ...
最新文章
- 使用 trait 时报PHP Parse error: syntax error, unexpected 'use' (T_USE) 这个错误
- ef mysql自动更新_EF Core中怎么实现自动更新实体的属性值到数据库
- HDU 1430 关系映射 + 打表 .
- deep learning:RBM公式推导+源码 ----- C++
- psp能装安卓软件吗_客户crm 软件能定制吗
- python安装pyqt5第三方_搭建pyqt5开发环境(python3+pycharm2019+pyqt5)
- linux文件读保护,Linux Rootkit实现文件保护
- LG P4899 [IOI2018] werewolf 狼人(kruskal重构树,二维数点)
- Sencha touch API
- CaseStudy-数据缓存出错
- 20145302张薇 《信息安全系统设计基础》第14周学习总结
- grub配置文件丢失的解决方法
- OpenCV-图像处理(30、轮廓周围绘制矩形框和圆形框)
- 二级mysql刷题_计算机二级通手机版(计算机二级刷题软件)V1.1 简化版
- MongoDB——聚合管道之$group操作
- 高云FPGA系列教程(2):FPGA点灯工程创建、程序下载和固化
- Google设置应用专用密码
- 微信小程序点赞成功,取消点赞、评论。
- MySQL中查看数据库
- html复习第七天 京东首页布局完成
热门文章
- 在ubuntu 14.04 64bit下配置安装PyQt4(python2.7和python3.4)
- 虚幻引擎的数学知识学习教程 Math for Unreal Engine (Early Preview)
- 游戏风格化角色创建入门指南视频教程
- MMSE(Minimum Mean Square Error)
- s-seq 生成序列化数字
- Qt 编译一直死循环问题
- Educational Codeforces Round 45 (Rated for Div. 2) D	 Graph And Its Complement(图的构造)
- Thrift源码解析--TBinaryProtocol
- 《学习OpenCV》第三章习题 第3题
- iPhone App开发实战手册学习笔记(5)之IOS常用机制