浅谈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中的zipfile模块使用详解
Jun 25 Python
python函数局部变量用法实例分析
Aug 04 Python
python脚本设置系统时间的两种方法
Feb 21 Python
Python的Flask框架中配置多个子域名的方法讲解
Jun 07 Python
将Dataframe数据转化为ndarry数据的方法
Jun 28 Python
OpenCV2从摄像头获取帧并写入视频文件的方法
Aug 03 Python
Python控制Firefox方法总结
Jun 03 Python
深入了解Django中间件及其方法
Jul 26 Python
django实现用户注册实例讲解
Oct 30 Python
keras:model.compile损失函数的用法
Jul 01 Python
PyCharm最新激活码(2020/10/27全网最新)
Oct 27 Python
Python+Selenium实现抖音、快手、B站、小红书、微视、百度好看视频、西瓜视频、微信视频号、搜狐视频、一点号、大风号、趣头条等短视频自动发布
Apr 13 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不用正则采集速度探究总结
2008/03/24 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
ThinkPHP进程计数类Process用法实例详解
2015/09/25 PHP
php中namespace及use用法分析
2016/12/06 PHP
ThinkPHP5与单元测试PHPUnit使用详解
2020/02/23 PHP
ExtJs事件机制基本代码模型和流程解析
2010/10/24 Javascript
jQuery 自定义函数写法分享
2012/03/30 Javascript
javascript验证身份证完全方法具体实现
2013/11/18 Javascript
Jquery 动态生成表格示例代码
2013/12/24 Javascript
JavaScript变量声明详解
2014/11/27 Javascript
JavaScript中的继承方式详解
2015/02/11 Javascript
黑帽seo劫持程序,js劫持搜索引擎代码
2015/09/15 Javascript
seajs加载jquery时提示$ is not a function该怎么解决
2015/10/23 Javascript
一起学写js Calender日历控件
2016/04/14 Javascript
js简单实现调整网页字体大小的方法
2016/07/23 Javascript
使用jquery/js获取iframe父子级、同级获取元素的方法
2016/08/05 Javascript
jquery实现全选、不选、反选的两种方法
2016/09/06 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
Echart折线图手柄触发事件示例详解
2018/12/16 Javascript
详解javascript 变量提升(Hoisting)
2019/03/12 Javascript
Vue的data、computed、watch源码浅谈
2020/04/04 Javascript
Vue 防止短时间内连续点击后多次触发请求的操作
2020/11/11 Javascript
对于Python中线程问题的简单讲解
2015/04/03 Python
Python批量合并有合并单元格的Excel文件详解
2018/04/05 Python
Python字符串内置函数功能与用法总结
2019/04/16 Python
Python3.5基础之NumPy模块的使用图文与实例详解
2019/04/24 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
2019/12/04 Python
分享PyCharm最新激活码(真永久激活方法)不用每月找安装参数或最新激活码了
2020/12/27 Python
一款利用纯css3实现的win8加载动画的实例分析
2014/12/11 HTML / CSS
在网络中有两台主机A和B,并通过路由器和其他交换设备连接起来,已经确认物理连接正确无误,怎么来测试这两台机器是否连通?如果不通,怎么来判断故障点?怎么排
2014/01/13 面试题
C# Debug和Testing相关面试题
2015/10/25 面试题
外国语学院毕业生自荐信
2013/10/28 职场文书
会计专业毕业生求职信分享
2014/01/03 职场文书
捐款倡议书范文
2014/02/02 职场文书
文秘班元旦晚会活动策划方案
2014/08/28 职场文书
向国旗敬礼学生寄语大全
2014/09/30 职场文书