zoukankan      html  css  js  c++  java
  • python-类继承与重用

    类的继承与重用

    一、什么是继承?

      1、继承是类与类间的关系。

      2、是一种什么‘’是‘’什么的关系。

      3、继承功能就是用来解决代码重用的问题。

    1、继承: 是一种创建新类的方式,

      python中,

      1、新建的类可以继承一个或多个父类。

      2、父类可以成为基类或超类。

      3、所新建的类称为子类或派生类。

    2、类继承的数量:

      python中类的继承分为:继承一个或多个。

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
        pass
    类继承1个或多个父类

    3、查看继承:

      python中可以通过__base__命令可以查看

    SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    #(<class '__main__.ParentClass1'>,)
    SubClass2.__bases__
    #(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
    __base__方法查看继承了什么类

    4、如果没有指定基类,python的类会默认继承object类,因为object类是所有python类的基类。

     ParentClass1.__bases__ #由于ParentClass1这个类中没有继承类,python默认会继承object类,打印如下:

     #(<class 'object'>,)

    5、经典类与新式类,及其区别。

      1、python2——才有经典与新式的区分。python3——统一都是新式类。

      2、python2——没有显式继承object的类的,以及该类的子类,都是经典类。声明了object的类及子类,都是新式类。

      3、python3——无论是否继承object,都默认继承object,因为python3所有的类都是新式类。

      4、经典类与新式类的主要区别在:

         经典类——多继承的情况,要查找的属性不存在时,按照深度优先。

         新式类——。。。。。。。按照广度优先。

    二、继承与抽象(先抽象再继承)

       抽象——抽取类似或相似的部分。

       继承——是抽象后的结果,通过编程来实现,一定要先有抽象的过程,才能有继承的结果。

    抽象的过程——提取对象相似的特征构造成类,然后通过类,再抽象成这些类的父类。

    继承的过程如下图。

    三、继承与重用性

      我们定义了一个类称A,再定义一个新类B,如果B这个类中有大部分的内容与A相同时。

      我们就可以用到类的继承的概念。通过继承,B就会遗传A所有的属性(包括数据和函数),从而实现代码重用。

    class Hero:
        def __init__(self,nickname,aggressivity,life_value):
            self.nickname=nickname
            self.aggressivity=aggressivity
            self.life_value=life_value
    
        def move_forward(self):
            print('%s move forward' %self.nickname)
    
        def move_backward(self):
            print('%s move backward' %self.nickname)
    
        def move_left(self):
            print('%s move forward' %self.nickname)
    
        def move_right(self):
            print('%s move forward' %self.nickname)
    
        def attack(self,enemy):
            enemy.life_value-=self.aggressivity
    class Garen(Hero):
        pass
    
    class Riven(Hero):
        pass
    
    g1=Garen('草丛伦',100,300)
    r1=Riven('锐雯雯',57,200)
    
    print(g1.life_value) #结果:300
    r1.attack(g1)
    print(g1.life_value) #结果:243
    通过继承实现代码重用

    注意:1、用已有的类建立新的类,可大大节省代码。

         2、 我们也可以继承被人的类如标准库,来定制新的类型。

    四、属性查找 

    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):  # 4、找到f2了执行命令
            print('Foo.f2')
            self.f1()  # 5、因为self 指的是对象本身,所以是b.f1()
            # 6、从bar()里找到f1() 所以打印Bar.f1
    
    
    class Bar(Foo):  # 3、在自己的类里面也没找到,所以在父类FOO里找
        def f1(self):
            print('Bar.f1')
    
    
    b = Bar()  # 2、从自己的类里面查找f1()
    b.f2()  # 1、从对象b里查找f1(),由于没有定义__init__方法,所以找不到。
    属性查找顺序

    查找说明:

      1、程序实例化了b=Bar()这个对象。

      2、b.f2()这个方法在b 这个类里找不到,就找从FOO这个类里找.

      3、在父类FOO中找到了f2()方法并执行。

      4、当执行self.f1()时,由于self指的是类本身即Bar,所以执行Bar下的f1()。

    五、派生

    类可以继承父类的属性,也可以自己新属于自己的属性,一旦定义的属性名与父类的重名,调用的时候以自己的为准。

    # 派生
    class Hero:
        def __init__(self, nickname, aggressivity, life_value):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_value = life_value
    
        def move_forward(self):
            print('%s move forward' % self.nickname)
    
        def move_backward(self):
            print('%s move backward' % self.nickname)
    
        def move_left(self):
            print('%s move forward' % self.nickname)
    
        def move_right(self):
            print('%s move forward' % self.nickname)
    
        def attack(self, enemy):
            enemy.life_value -= self.aggressivity
    
    
    class Riven(Hero):
        camp = 'Noxus'
    
        def attack(self, enemy):  # 在自己这里定义新的attack,不再使用父类的attack,且不会影响父类
            print('from riven', enemy)
    
        def fly(self):  # 在自己这里定义新的
            print('%s is flying' % self.nickname)
    
    
    r1 = Riven('锐雯雯', 57, 200)
    print(r1.attack(10))
    派生用法

    注意:在子类中,如果新建了与父类重名的函数属性,在调用时也应该按照函数调用方式进行,即有多少个参数应传多少个值

    六、继承的实现原理

    Python实现继承的原理是在用户定义类的时候,计算并生成一个MRO线性列表。主要有如下原则:

      1、子类优先于父类查找

      2、多个父类会根据MRO列表顺序查找

      3、如果下一个类对应两个合法选项,第一个父类优先。

    注意:C和java只支持继承一个父类,python支持继承多个父类,如果继承多个父类,查找方式有两种:

      经典类——深度优先:

      新式类——广度优先

    在python3查找顺序练习:

    class A(object):
        def test(self):
            print('from A')
    
    
    class B(A):
        def test(self):
            print('from B')
    
    
    class C(A):
        def test(self):
            print('from C')
    
    
    class D(B):
        def test(self):
            print('from D')
    
    
    class E(C):
        def test(self):
            print('from E')
    
    
    class F(D, E):
        # def test(self):
        #     print('from F')
        pass
    
    
    f1 = F()
    f1.test()  # F D B E C A
    
    print(F.__mro__)  # 只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    # 新式类继承顺序:F->D->B->E->C->A
    # 经典类继承顺序:F->D->B->A->E->C
    # python3中统一都是新式类
    # pyhon2中才分新式类与经典类
    py3多个父类查找方式

    由于py3的类统一是新式类,按照广度优先查找顺序,所以查找顺序为F=>D=>B=>E=>C=>A

    如果是在py2,是经典类,按深度优先,所以是这样的F=>D=>B=>A=>E=>C

    七、子类中调用父类的方法

      有两种方法:

      1、指名道姓调用

    # 1、指名道姓方式引用,这种方式跟继承没有关系,只是简单的类的函数属性的引用
    class Vehicle:  # 定义交通工具类
        Country = 'China'
    
        def __init__(self, name, speed, load, power):
            self.name = name
            self.speed = speed
            self.load = load
            self.power = power
    
        def run(self):
            print('开动啦...')
    
    
    class Subway(Vehicle):  # 地铁
        def __init__(self, name, speed, load, power, line):
            Vehicle.__init__(self, name, speed, load, power) #指名道姓引用类的函数属性,
                                                             # 相当于引用了类的函数属性,需要什么参数要传什么参数
            self.line = line                                 # 新增子类属性
    
        def run(self):
            print('地铁%s号线欢迎您' % self.line)
            Vehicle.run(self)
    
    
    line13 = Subway('中国地铁', '180m/s', '1000人/箱', '', 13)
    line13.run()
    指名道姓引用类函数属性

    注意:这样的调用方式,跟继承没有关系,相当于引用了类的函数属性,需要什么参数就要传什么参数。

      2、super()方法调用

    # 调用方法二:super()
    #A没有继承B,但是A内super会基于C.mro()继续往后找
    class A:
        def test(self):
            print('test A')
            super().test()
    class B:
        def test(self):
            print('from B')
    class C(A,B):
        # print('test c')
        pass
    
    c=C()
    c.test() #打印结果:from B
    Super()方法调用

    注意:用super方法调用,是依赖于继承的,即使两个父类间没有继承关系,都会从子类的继承关系的MRO表继续往后找。

  • 相关阅读:
    python模块—socket
    mac os系统的快捷键
    教你如何将UIImageView视图中的图片变成圆角
    关于ASP.NET MVC
    iOS 日期格式的转换
    将App通过XCode上传到AppStore 出现这个错误“An error occurred uploading to the iTunes Store”的解决方法
    关于MAC OS下面两个软件的功能改进——Dictionary和Fit 输入法
    分享一下上个星期的香港行程
    【博客园IT新闻】博客园IT新闻 iPhone 客户端发布
    解决Entity Framework Code First 的问题——Model compatibility cannot be checked because the database does not contain model metadata
  • 原文地址:https://www.cnblogs.com/AYxing/p/8996824.html
Copyright © 2011-2022 走看看