Python——继承

摘要:
Python继承是一种多重继承机制。一个子类可以同时具有多个直接父类;继承可以获得父类定义的方法,子类可以重用父类的方法。在上面的示例中,Myself类继承了Animal类和Child类。当Myself子类对象调用name()方法时,因为name()没有在Myself类中定义,Python将首先在Animal父类中搜索name(),一旦找到,它将停止向下搜索,因此它在Animals类中运行name();在Yourself子类中,由于Child的父类排名第一,Child类的name()方法将运行。

Python的继承是多继承机制,一个子类可以同时有多个直接父类;继承可以得到父类定义的方法,子类就可以复用父类的方法。

一、继承的语法

子类:实现继承的类。

父类(基类、超类):被继承的类。

子类继承父类是在定义子类时,将多个父类放在子类之后的圆括号内,如果定义类时,未指定这个类的直接父类,则默认继承object类,所以object类是所有类的父类(直接父类或者是间接父类)。

语法格式如下:

class SubClass (SuperClassl , SuperClass2 , ... ):
    # 类定义部分

使用例子:

class Animal:
    def dog(self):
        print ('我有一只狗!他叫%s'%self.dog_name)

class Child:
    def son(self):
        print ('我有两个儿子!')

# 定义Myself类,继承Animal类和Child类
class Myself(Animal,Child):
    def name(self):
        print ('我叫小明!')

M = Myself()    # 创建Myself对象
M.dog_name = '大黄'   # 通过Myself对象添加dog_name类变量
M.dog() # 调用Myself对象的dog()方法,打印 我有一只狗!他叫大黄
M.son() # 调用Myself对象的son()方法,打印 我有两个儿子!
M.name()    # 调用Myself对象的name()方法,打印 我叫小明!

在上面的例子中,定义了Animal和Child两个父类,和一个继承Animal类和Child类的Myself类;创建Myself对象后,可以访问Myself对象的dog()方法和son()方法,说明Myself对象也具有dog()方法和son()方法,所以继承可以得到父类定义的方法,通过继承子类就可以复用父类的方法。

二、多继承

子类会通过继承得到所有父类的方法,那么如果多个父类中有相同的方法名,排在前面的父类同名方法会“遮蔽”排在后面的父类同名方法,例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黄!')

class Child:
    def name(self):
        print ('我有两个儿子!')

class Myself(Animal,Child):
    pass

class Yourself(Child,Animal):
    pass

M = Myself()
M.name()    # 打印 我有一只狗,他叫大黄!
Y = Yourself()
Y.name()    # 打印 我有两个儿子!

上面例子中,Myself类继承了Animal类和Child类,当Myself子类对象调用name()方法时,因为Myself子类中没有定义name()方法,Python会先在Animal父类中搜寻name()方法,一旦搜寻到就会停止继续向下搜寻,所以运行的是Animal类中的name()方法;而Yourself子类中由于Child父类排在前面,所以运行的是Child类的name()方法。

三、重写

子类包含与父类同名的方法称为方法重写(方法覆盖),可以说是重写父类方法,也可以说子类覆盖父类方法。

例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黄!')


class Myself(Animal):
    # 重写Animal类的name()方法
    def name(self):
        print ('我没有狗,我只有一只猫,他叫大白!')


M = Myself()    # 创建Myself对象
M.name()    # 执行Myself对象的name()方法,打印 我没有狗,我只有一只猫,他叫大白!

上面的例子中,运行M.name()时执行的不再是Animal类的fly()方法,而是Myself类的name()方法。

在子类中重写方法之后,如果需要用到父类中被重写的实例方法,可以通过类名调用实例方法来调用父类被重写的方法。

例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黄!')

class Myself(Animal):
    # 重写Animal类的name()方法
    def name(self):
        print ('我还有一只猫,他叫大白!')

    def pet(self):
        Animal.name(self)   # 调用被重写的父类方法name(),使用类名.实例名调用,需要手动传self
        self.name() # 执行name()方法,会调用子类重写的name()方法
      
  
M = Myself()    # 创建Myself对象
M.pet()
'''
打印
我有一只狗,他叫大黄!
我还有一只猫,他叫大白!
'''

  

四、super函数调用父类构造方法

如果子类有多个直接的父类,那么排在前面的构造方法会遮蔽排在后面的构造方法。

例:

class Animal:
    def __init__(self,pet,name):
        self.pet = pet
        self.name = name
        
    def favourite_animal(self):
        print ('我有一只%s,他叫%s!'%(self.pet,self.name))

class Fruit:
    def __init__(self,kind):
        self.kind = kind
        
    def favourite_fruit(self):
        print ('我喜欢的水果是%s!'%self.kind)


class Myself(Animal,Fruit):
    pass
        

M = Myself('狗','大黄')    # 创建Myself对象
M.favourite_animal()    # 调用Myself对象的favourite_animal()方法,打印 我有一只狗,他叫大黄!
M.favourite_fruit() # 调用Myself对象的favourite_fruit方法,由于未初始化Fruit对象的kind实例变量,报错 AttributeError: 'Myself' object has no attribute 'kind'

上面例子中,Myself子类继承了Animal父类和Fruit父类,由于Animal父类排在Fruit父类前面,所以Animal父类的构造函数遮蔽了Fruit父类的构造函数,运行M.favourite_animal()没有任何问题,当运行M.favourite_fruit()时,由于未初始化Fruit对象的kind实例变量,所以程序会报错。

解决以上问题,Myself应该重写父类的构造方法,子类的构造方法可以调用父类的构造方法,有以下两种方式:

1.使用未绑定方法,即: 父类名.__init__(self,参数1,参数2....)。

2.使用super()函数调用父类构造方法。

先查看一下super()函数的帮助信息,

>>> help(super)
Help on class super in module builtins:

class super(object)
 |  super() -> same as super(__class__, <first argument>)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super().meth(arg)
 |  This works for class methods too:
 |  class C(B):
 |      @classmethod
 |      def cmeth(cls, arg):
 |          super().cmeth(arg)
...

通过帮助信息,可以看到,当调用父类的实例方法时,会自动绑定第一个参数self;当调用类方法时,会自动绑定第一个参数cls。

接下来修改上面的程序:

class Animal:
    def __init__(self,pet,name):
        self.pet = pet
        self.name = name
        
    def favourite_animal(self):
        print ('我有一只%s,他叫%s!'%(self.pet,self.name))

class Fruit:
    def __init__(self,kind):
        self.kind = kind
        
    def favourite_fruit(self):
        print ('我喜欢的水果是%s!'%self.kind)


class Myself(Animal,Fruit):
    def __init__(self,pet,name,kind):
        Fruit.__init__(self,kind)   # 通过未绑定方法调用父类构造方法
        super().__init__(pet,name)  # 通过super()函数调用父类构造方法
        
        
               

M = Myself('狗','大黄','苹果')
M.favourite_animal()    # 打印 我有一只狗,他叫大黄!
M.favourite_fruit()     # 打印 我喜欢的水果是苹果!

  

免责声明:文章转载自《Python——继承》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Node.js安装与配置导入shape文件到SDE数据库下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

如何在交互式环境中执行Python程序

相信接触过Python的小伙伴们都知道运行Python脚本程序的方式有多种,目前主要的方式有:交互式环境运行、命令行窗口运行、开发工具上运行等,其中在不同的操作平台上还互不相同。今天,小编讲些Python基础的内容,以Windows下交互式环境为依托,演示Python程序的运行。 一般来说,顺利安装Python之后,有两种方式可以进入Python交互性环...

Python什么是二次开发的意义?python在.net项目采用

任何人都知道python在.net该项目是做什么的啊? 辅助用途,用作“二次开发”。.net站点的话python主要是CGI才用。能够用python编写B/S程序。 解释一下二次开发: 对于Python来说。他本身未定义主函数 , 和LUA一样,他们都是解释语言,须要一个拥有主函数的主语言帮助解释。那么不管是在C/C++/JAVA/C#中都是一样...

dmidecode的Python解析

#!/usr/bin/env python # -*- coding: utf-8 -*- """ 解析dmidecode命令输出结果,返回JSON格式数据 测试服务器Dell VMware虚拟机 测试系统为CentOS 6.x 7.x Python版本为Python3.6 原版参考的是 https://pypi.org/project/dm...

[Python之路] 多种方式实现并发Web Server

下面我们使用Python来实现并发的Web Server,其中采用了多进程、多线程、协程、单进程单线程非阻塞的方式。 一、使用子进程来实现并发Web Server 参照 https://www.cnblogs.com/leokale-zz/p/11949208.html 中的代码,我们将其修改为支持并发的简单Web Server: import socke...

Python中利用os模块创建目录文件

一、os.makedirs()   os.makedirs() 方法用于递归创建目录。像 mkdir(), 但创建的所有intermediate-level文件夹需要包含子目录。 import os path_01 = 'Test\path_01\path_02\path_03' try: os.mkdir(path_01) print...

[Python]IO密集型任务 VS 计算密集型任务

所谓IO密集型任务,是指磁盘IO、网络IO占主要的任务,计算量很小。比如请求网页、读写文件等。当然我们在Python中可以利用sleep达到IO密集型任务的目的。 所谓计算密集型任务,是指CPU计算占主要的任务,CPU一直处于满负荷状态。比如在一个很大的列表中查找元素(当然这不合理),复杂的加减乘除等。 多线程即在一个进程中启动多个线程执行任务。一般来...