浅谈Python类的单继承相关知识


Posted in Python onMay 12, 2021

一、类的继承

面向对象三要素之一,继承Inheritance

人类和猫类都继承自动物类。

个体继承自父母,继承了父母的一部分特征,但也可以有自己的个性。

在面向对象的世界中,从父类继承,就可以直接拥有父类的属性和方法,这样就可以减少代码、多服用。子类可以定义自己的属性和方法

class Animal:
 
    def __init__(self,name):
        self._name = name
 
    def shout(self):
        print("{}  shouts".format(self.__class__.__name__))
    @property
    def name(self):
        return self._name
 
 
class Cat(Animal):
    pass
 
 
class Dog(Animal):
    pass
 
a = Animal("monster")
a.shout()           #   Animal  shouts
 
 
cat = Cat("garfield")
cat.shout()         #   Cat  shouts
print(cat.name)     #   garfield
 
 
dog = Dog("ahuang")
dog.shout()         #   Dog  shouts
print(dog.name)     #   ahuang

上例中我们可以看出,通过继承、猫类、狗类不用写代码,直接继承了父类的属性和方法

继承:

  • class Cat(Animal)这种形式就是从父类继承,括号中写上继承的类的列表。
  • 继承可以让子类重父类获取特征(属性、方法)

父类:

  • Animal就是Cat的父类,也称为基类、超类

子类:

  • Cat 就是Animal的子类,也成为派生类  

二、继承的定义、查看继承的特殊属性和方法

格式

class 子类 (基类1[,基类2,……]):
    语句块

如果类定义时,没有基类列表,等同于继承自【object】。在Python3中,【object】类是所有对象基类

查看继承的特殊属性和方法

特殊属性  含义 示例
__base__  类的基类   
__bases__  类的基类元组   
__mro__  显示方法查找顺序,基类的元组   
mro()  同上  int.mro()
__subclasses__()  类的子类列表  int.__subclasses__()

三、继承中的访问控制

class Animal:
    __COUNT = 100
    HEIGHT = 0
 
    def __init__(self,age,weight,height):
        self.__COUNT += 1
        self.age = age
        self.__weight = weight
        self.HEIGHT = height
 
    def eat(self):
        print("{}  eat".format(self.__class__.__name__))
 
    def __getweight(self):
        print(self.__weight)
 
    @classmethod
    def showcount1(cls):
        print(cls.__COUNT)
 
    @classmethod
    def __showcount2(cls):
        print(cls.__COUNT)
 
    def showcount3(self):
        print(self.__COUNT)
 
class Cat(Animal):
    NAME = "CAT"
    __COUNT = 200
 
#a = Cat()              #   TypeError: __init__() missing 3 required positional arguments: 'age', 'weight', and 'height'
a = Cat(30,50,15)
a.eat()                 #   Cat  eat
print(a.HEIGHT)         #   15
#print(a.__COUNT)        #   AttributeError: 'Cat' object has no attribute '__COUNT'
#print(a.__showcount2)   #   AttributeError: 'Cat' object has no attribute '__showcount2'
#print(a.__getweight)    #   AttributeError: 'Cat' object has no attribute '__getweight'
a.showcount3()   #   101
a.showcount1()   #  100
print(a.NAME)    #    CAT
 
print(Animal.__dict__)  #   {'__module__': '__main__', '_Animal__COUNT': 100, 'HEIGHT': 0, '__init__': <function Animal.__init__ at 0x020DC228>, 'eat': <function Animal.eat at 0x020DC468>, '_Animal__getweight': <function Animal.__getweight at 0x02126150>, 'showcount1': <classmethod object at 0x020E1BD0>, '_Animal__showcount2': <classmethod object at 0x020E1890>, 'showcount3': <function Animal.showcount3 at 0x021264F8>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}
print(Cat.__dict__)     #   {'__module__': '__main__', 'NAME': 'CAT', '_Cat__COUNT': 200, '__doc__': None}
print(a.__dict__)       #   {'_Animal__COUNT': 101, 'age': 30, '_Animal__weight': 50, 'HEIGHT': 15}

从父类继承、自己没有的,就可以到父类中找

私有的都是不可访问的,但是本质上依然是改了名称放在这个属性所在的类的了【__dict__】中,知道这个新民成就可以了直接找到这个隐藏的变量,这是个黑魔法慎用

总结

  • 继承时,共有的,子类和实例都可以随意访问;私有成员被隐藏,子类和实例不可直接访问,当私有变量所在类内方法中可以访问这个私有变量
  • Python通过自己一套实现,实现和其他语言一样的面向对象的继承机制

属性查找顺序:实例的【__dict__】------类的【__dict__】-----父类【__dict__】

如果搜索这些地方后没有找到异常,先找到就立即返回

四、方法的重写、覆盖override

class Animal:
 
    def shout(self):
        print("Animal shouts")
 
class Cat(Animal):
 
    def shout(self):
        print("miao")
 
a = Animal()
a.shout()       #   Animal shouts
b  = Cat()
b.shout()       #   miao
 
print(a.__dict__)       #   {}
print(b.__dict__)       #   {}
print(Animal.__dict__)  #   {'__module__': '__main__', 'shout': <function Animal.shout at 0x017BC228>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}

Cat类中shout为什么没有打印Animal中shout的方法,方法被覆盖了?

  • 这是因为,属性查找顺序:实例的【__dict__】------类的【__dict__】-----父类【__dict__】

那子类如何打印父类的同命的方法

  • super()可以访问到父类的属性
class Animal:
 
    def shout(self):
        print("Animal shouts")
 
class Cat(Animal):
 
    def shout(self):
        print("miao")
 
    def shout(self):
        print("super():   " , super())
        print(super(Cat, self))
        super().shout()
        super(Cat,self).shout()   # 等价于super().shout()
        self.__class__.__base__.shout(self)  #不推荐使用
 
a = Animal()
a.shout()       #   Animal shouts
b  = Cat()
b.shout()       #   super():    <super: <class 'Cat'>, <Cat object>>
                #   <super: <class 'Cat'>, <Cat object>>
                #   Animal shouts
                #   Animal shouts
                #   Animal shouts
print(a.__dict__)       #   {}
print(b.__dict__)       #   {}
print(Animal.__dict__)  #   {'__module__': '__main__', 'shout': <function Animal.shout at 0x019AC228>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}
print(Cat.__dict__)     #   {'__module__': '__main__', 'shout': <function Cat.shout at 0x019F6150>, '__doc__': None}

super(Cat,self).shout()的作用相当于

  • 调用,当前b的实例中找cat类基类中,shout的方法

那对于类方法和静态方法是否也同样适用尼?

class Animal:
    @classmethod
    def class_method(cls):
        print("class_method")
 
    @staticmethod
    def static_method():
        print("static_methond_animal")
 
class Cat(Animal):
    @classmethod
    def class_method(cls):
        super().class_method()  #   class_method
        print("class_method_cat")
 
    @staticmethod
    def static_method(cls,self):
        super(Cat,self).static_method()
        print("static_method_cat")
 
b = Cat()
b.class_method()    #   class_method
                    #   class_method_cat
b.static_method(Cat,b)
                    #   static_methond_animal
                    #   static_method_cat

这些方法都可以覆盖,原理都一样,属性字典的搜索顺序

五、继承中的初始化

看以下一段代码,有没有问题

class A:
    def __init__(self,a):
        self.a = a
 
class B(A):
    def __init__(self,b,c):
        self.b = b
        self.c = c
 
    def printv(self):
        print(self.b)
        print(self.a)
 
a = B(100,300)
print(a.__dict__)       #   {'b': 100, 'c': 300}
print(a.__class__.__bases__)    #   (<class '__main__.A'>,)
a.printv()      #   100
                #   AttributeError: 'B' object has no attribute 'a'

上例代码

  • 如果B类定义时声明继承自类A,则在B类中__bases__中是可以看到类A
  • 这和是否调用类A的构造方法是两回事
  • 如果B中调用了A的构造方法,就可以拥有父类的属性了,如果理解这一句话?
class A:
    def __init__(self,a):
        self.a = a
 
class B(A):
    def __init__(self,b,c):
        super().__init__(b+c)
        # A.__init__(self,b+c)
        self.b = b
        self.c = c
 
    def printv(self):
        print(self.b)
        print(self.a)
 
a = B(100,300)
print(a.__dict__)       #   {'a': 400, 'b': 100, 'c': 300}
print(a.__class__.__bases__)    #   (<class '__main__.A'>,)
a.printv()      #   100
                #   400

作为好的习惯,如果父类定义了__init__方法,你就改在子类__init__中调用它【建议适用super()方法调用】

那子类什么时候自动调用父类的【__init__】方法?

例子一:【B实例的初始化会自动调用基类A的__init__方法】

class A:
    def __init__(self):
        self.a1 = "a1"
        self.__a2 = "a2"
        print("A init")
 
class B(A):
    pass
 
b = B()     #   A init
print(b.__dict__)   #   {'a1': 'a1', '_A__a2': 'a2'}

例子二:【B实例的初始化__init__方法不会自动调用父类的初始化__init__方法,需要手动调用】

class A:
    def __init__(self):
        self.a1 = "a1"
        self.__a2 = "a2"
        print("A init")
 
class B(A):
    def __init__(self):
        self.b1 = "b1"
        self.__b2 = "b2"
        print("b init")
        #A.__init__(self)
 
b = B()     #   b init
print(b.__dict__)   #   {'b1': 'b1', '_B__b2': 'b2'}

那如何正确实例化?

  • 注意,调用父类的__init__方法,出现在不同的位置,可能导致出现不同的结果
class Animal:
    def __init__(self,age):
        print("Animal init")
        self.age = age
 
    def show(self):
        print(self.age)
 
class Cat(Animal):
    def __init__(self,age,weight):
        #调用父类的__init__方法的顺序 决定show方法的结果
        super(Cat, self).__init__(age)
        print("Cat init")
        self.age = age + 1
        self.weight = weight
 
a = Cat(10,5)
a.show()        #   Animal init
                #   Cat init
                #   11

怎么直接将上例中所有的实例属性改变为私有属性?

  • 解决办法,一个原则,自己的私有属性,就该自己的方法读取和修改,不要借助其他类的方法,即父类或者派生类
class Animal:
    def __init__(self,age):
        print("Animal init")
        self.__age = age
 
    def show(self):
        print(self.__age)
 
class Cat(Animal):
    def __init__(self,age,weight):
        #调用父类的__init__方法的顺序 决定show方法的结果
        super(Cat, self).__init__(age)
        print("Cat init")
        self.__age = age + 1
        self.__weight = weight
 
    def show(self):
        print(self.__age)
 
a = Cat(10,5)
a.show()        #   Animal init
                #   Cat init
                #   11
print(a.__dict__)   #   {'_Animal__age': 10, '_Cat__age': 11, '_Cat__weight': 5}

到此这篇关于浅谈Python类的单继承相关知识的文章就介绍到这了,更多相关Python类的单继承内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python自动化工具日志查询分析脚本代码实现
Nov 26 Python
Python利用pyHook实现监听用户鼠标与键盘事件
Aug 21 Python
Python正则表达式使用经典实例
Jun 21 Python
Python 解决中文写入Excel时抛异常的问题
May 03 Python
matplotlib实现热成像图colorbar和极坐标图的方法
Dec 13 Python
python实现定时压缩指定文件夹发送邮件
Dec 22 Python
在Python中COM口的调用方法
Jul 03 Python
Flask中endpoint的理解(小结)
Dec 11 Python
Python如何在windows环境安装pip及rarfile
Jun 15 Python
Python操作Elasticsearch处理timeout超时
Jul 17 Python
Python如何将模块打包并发布
Aug 30 Python
Django和Ueditor自定义存储上传文件的文件名
Feb 25 Python
PyCharm 安装与使用配置教程(windows,mac通用)
在python中实现导入一个需要传参的模块
May 12 #Python
python 使用Tensorflow训练BP神经网络实现鸢尾花分类
PyTorch 如何设置随机数种子使结果可复现
May 12 #Python
Python Parser的用法
May 12 #Python
pytorch MSELoss计算平均的实现方法
May 12 #Python
Django如何创作一个简单的最小程序
May 12 #Python
You might like
PHP编程与应用
2006/10/09 PHP
apache集成php7.3.5的详细步骤
2019/06/20 PHP
在Laravel 的 Blade 模版中实现定义变量
2019/10/14 PHP
javascript 动态添加表格行
2006/06/22 Javascript
Mozilla中显示textarea中选择的文字
2006/09/07 Javascript
javascript  Error 对象 错误处理
2008/05/18 Javascript
国外的为初学者写的JavaScript教程
2008/06/09 Javascript
js Dialog 去掉右上角的X关闭功能
2014/04/23 Javascript
Nodejs+express+html5 实现拖拽上传
2014/08/08 NodeJs
JavaScript中对象介绍
2014/12/31 Javascript
JS实现简洁、全兼容的拖动层实例
2015/05/13 Javascript
js实现浮动在网页右侧的简洁QQ在线客服代码
2015/09/04 Javascript
jQuery Ajax传值到Servlet出现乱码问题的解决方法
2016/10/09 Javascript
Jquery UI实现一次拖拽多个选中的元素操作
2020/12/01 Javascript
JS实现仿PS的调色板效果完整实例
2016/12/21 Javascript
livereload工具实现前端可视化开发【推荐】
2016/12/23 Javascript
JQuery实现定时刷新功能代码
2017/05/09 jQuery
在vue 中使用 less的教程详解
2018/09/26 Javascript
NodeJs 文件系统操作模块fs使用方法详解
2018/11/26 NodeJs
js使用文档就绪函数动态改变页面内容示例【innerHTML、innerText】
2019/11/07 Javascript
vue.config.js中配置Vue的路径别名的方法
2020/02/11 Javascript
[24:42]VP vs TNC Supermajor小组赛B组 BO3 第三场 6.2
2018/06/03 DOTA
python实现2048小游戏
2015/03/30 Python
在Python中操作时间之mktime()方法的使用教程
2015/05/22 Python
Python如何安装第三方模块
2020/05/28 Python
Python faker生成器生成虚拟数据代码实例
2020/07/20 Python
英国排名第一的最新设计师品牌手表独立零售商:TIC Watches
2016/09/24 全球购物
迪梵英国官方网站:Darphin英国
2017/12/06 全球购物
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
骨干教师培训制度
2014/01/13 职场文书
青年文明号复核材料
2014/02/11 职场文书
七一建党节慰问信
2015/02/14 职场文书
2015年卫生院健康教育工作总结
2015/07/24 职场文书
汽车车尾标语大全
2015/08/11 职场文书
《雪地里的小画家》教学反思
2016/02/16 职场文书
MySQL分区以及建索引的方法总结
2022/04/13 MySQL