浅谈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 相关文章推荐
CentOS 6.5中安装Python 3.6.2的方法步骤
Dec 03 Python
Python基于更相减损术实现求解最大公约数的方法
Apr 04 Python
tensorflow saver 保存和恢复指定 tensor的实例讲解
Jul 26 Python
利用python打开摄像头及颜色检测方法
Aug 03 Python
pycharm重置设置,恢复默认设置的方法
Oct 22 Python
Django 静态文件配置过程详解
Jul 23 Python
python3使用GUI统计代码量
Sep 18 Python
Series和DataFrame使用简单入门
Nov 13 Python
python二维键值数组生成转json的例子
Dec 06 Python
QML用PathView实现轮播图
Jun 03 Python
Python数据相关系数矩阵和热力图轻松实现教程
Jun 16 Python
Python实现拼音转换
Jun 07 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
使用adodb lite解决问题
2006/12/31 PHP
php中session过期时间设置及session回收机制介绍
2014/05/05 PHP
php中删除数组的第一个元素和最后一个元素的函数
2015/03/07 PHP
Laravel 5.1 on SAE环境开发教程【附项目demo源码】
2016/10/09 PHP
img的onload的另类用法
2008/01/10 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2014/09/04 Javascript
Javascript基础教程之数据类型 (布尔型 Boolean)
2015/01/18 Javascript
JavaScript实现判断图片是否加载完成的3种方法整理
2015/03/13 Javascript
纯javascript模仿微信打飞机小游戏
2015/08/20 Javascript
AngularJS 遇到的小坑与技巧小结
2016/06/07 Javascript
原生js代码实现图片放大境效果
2016/10/30 Javascript
jQuery中Nicescroll滚动条插件的用法
2016/11/10 Javascript
js 轮播效果实例分享
2016/12/28 Javascript
vue2.0 资源文件assets和static的区别详解
2018/04/08 Javascript
详解vue-cli 构建项目 vue-cli请求后台接口 vue-cli使用axios、sass、swiper
2018/05/28 Javascript
Angular6中使用Swiper的方法示例
2018/07/09 Javascript
用vue-cli开发vue时的代理设置方法
2018/09/20 Javascript
小程序自定义日历效果
2018/12/29 Javascript
Javascript迭代、递推、穷举、递归常用算法实例讲解
2019/02/01 Javascript
详解关于Vuex的action传入多个参数的问题
2019/02/22 Javascript
[46:44]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
[12:29]2018国际邀请赛 开幕秀
2018/08/22 DOTA
Python中利用函数装饰器实现备忘功能
2015/03/30 Python
Python程序中用csv模块来操作csv文件的基本使用教程
2016/03/03 Python
如何基于Python实现电子邮件的发送
2019/12/16 Python
PyCharm无法引用自身项目解决方式
2020/02/12 Python
python-xpath获取html文档的部分内容
2020/03/06 Python
Python特殊属性property原理及使用方法解析
2020/10/09 Python
澳大利亚手袋、珠宝和在线时尚精品店:The Way
2019/12/21 全球购物
专科毕业生学习生活的自我评价
2013/10/26 职场文书
春风行动实施方案
2014/03/28 职场文书
投资意向书范本
2014/04/01 职场文书
文化建设工作方案
2014/05/12 职场文书
优秀班主任先进事迹材料
2014/12/16 职场文书
教师工作能力自我评价
2015/03/04 职场文书
机关干部作风整顿心得体会
2016/01/22 职场文书