• 面向对象三大特性之继承


    1.初识继承

    什么是继承

      继承是面向对象中的一个概念,是描述两个对象的关系,在程序中,继承描述的是类和类之间的关系

        例如:a继承了b,a就可以使用b的属性和方法.a称之为子类,b称之为父类,也叫基类

    为什么要使用继承

      继承的一方可以使用被继承一方已有的东西,这样可以提高代码的重用性

    如何使用继承

    继承的基本语法

     1 class A:
     2     # 父类中的方法和属性
     3     a = 1
     4     def a1(self):
     5         print('a1')
     6 
     7 class B(A):
     8     # 子类中的方法和属性
     9     pass
    10 b = B()  # 实例化子类B的对象b
    11 print(b.a)  # 使用父类A中的属性
    12 b.a1()  # 使用父类A中的方法

    2.抽象与继承

    抽象即抽取一系列对象或类中相同的部分,从而形成一个新的类

    抽象的两个层次:

      1.将一系列具有相同特征和行为的对象抽取成类

      2.将一系列具有相同属性和方法的类抽取成父类

    继承是基于抽象的结果,通过编程语言实现它,先经历抽象的过程,才能通过继承的方法表达抽象的结果

    正确的使用继承:

      1.先抽象再继承

      2.继承一个已经存在的类,扩展或是修改原始的功能

     

    3.属性的查找顺序

    属性的查找顺序:对象---->类---->父类---->父类的父类---->.....直到object

     1 # 属性的查找顺序
     2 class A:  # 父类A定义了一个x
     3     x = 1
     4 
     5 class B(A):  # 子类B也定义了一个x
     6     x = 2
     7 
     8 b = B()
     9 print(b.x)  # 在对象定义之前查找是查找子类B中
    10 b.x = 3  # 对象也定义了一个x
    11 print(b.x)  # 定义x之后,是在对象的属性中查找

    先去对象中找,找不到再去类中找,找不到再去父类中找,一直找到object为止,找不到就报错

    4.派生与覆盖

    什么是派生类

      当一个子类中出现了与父类中不同的内容时,这个子类就称之为派生类.通常情况下,我们不可能写一个和父类完全一模一样的子类,这样就失去了子类的意义,我们都会加一些代码,所以子类基本都是派生类.

     1 # 派生类
     2 class Person:
     3     def say_hi(self):  # 父类中有一个方法
     4         print('hi')
     5 
     6 class Student(Person):
     7     def say_hello(self):  # 子类中也有一个新的方法
     8         print('hello')  # 此时这个子类就叫做派生类
     9 
    10 s1 = Student()  # 实例化一个类的对象
    11 s1.say_hi()  # 子类的对象可以调用父类的方法
    12 s1.say_hello()

    覆盖也称重写(overrides),当子类出现了和父类名称完全一致的属性或者方法时就叫做覆盖

     1 # 覆盖
     2 class Person:
     3     x = 1  # 父类中有一个属性
     4     def say_hi(self):  # 父类中有一个方法
     5         print('hi')
     6 
     7 class Student(Person):
     8     x = 2  # 子类中有一个同名的属性
     9     def say_hi(self):  # 子类中也有一个同名的方法
    10         print('hello')
    11 
    12 s1 = Student()
    13 print(s1.x)  # 打印的是子类中的属性
    14 s1.say_hi()  # 打印的是子类中的方法

    5.子类访问父类的内容

    访问的语法

    语法:
    ```python
    方式1:
    super(当前类名称,self).你要调的父类的属性或方法
    方式2:
    super().你要调的父类的属性或方法
    方式3:
    类名称.你要调的父类的属性或方法(self)  
    #方式3与继承无关 
    ```

    子类访问父类的例子

     1 # 子类访问父类的内容
     2 class Person:
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6 
     7     def eat(self):
     8         print('%s会吃东西'%self.name)
     9 
    10 class Student(Person):
    11     def __init__(self,name,age,id):
    12         # 第一种,父类名直接调用,这种方法什么地方都可以调用,与继承无关,并且需要写上对象本身
    13         Person.__init__(self,name,age)
    14         # 第二种,super(类名,对象本身),是python2内置的
    15         super(Student,self).__init__(name,age)
    16         # 第三种,python3做了优化可以内部不传参,推荐使用
    17         super().__init__(name,age)
    18         self.id = id
    19 
    20     def eat(self):
    21         super().eat()  # 第三种方法在访问父类的方法
    22         super(Student,self).eat()  # 第二种方法在访问父类的方法
    23         print('%s吃更好的东西'%self.name)
    24 
    25 s1 = Student('sxc',18,188)
    26 s1.eat()

    初始化方法必须调用super

    当你继承一个现有的类,并且你覆盖了父类的init方法时,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需的参数

    需求:person父类中有name,age两个属性,子类student中我需要增加一个id的属性

     1 # 继承中初始化方法必须调用super
     2 class Person:
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6 
     7 class Student(Person):
     8     def __init__(self,name,age,id):  # 当子类需要增加属性时,需要再初始化一次,这时会覆盖父类的初始化方法
     9         super().__init__(name,age)  # 子类初始化方法必须加super,这样就能导入父类的初始化方法
    10         self.id = id  # 增加了id属性,原属性也能访问
    11 
    12     def say(self):
    13         print('%s说我真帅'%self.name)  # 如果不初始化方法不调用super,self.name就找不到,会报错
    14 
    15 s1 = Student('sxc',18,1414)
    16 s1.say()

    练习:实现一个可以限制元素类型的容器(字符串,元组,列表,字典,集合)

     1 # 实现一个可以限制元素类型的容器 (字典,列表,元组,集合,字符串)
     2 class Newlist(list):
     3     def __init__(self,kind):
     4         super().__init__()  # 调用父类的初始化方法
     5         self.kind = kind
     6 
     7     def append(self,obj):
     8         if type(obj) == self.kind:
     9             super().append(obj)  # 调用父类的append方法
    10             print('加入成功')
    11         else:
    12             print('类型错误')
    13 
    14 n = Newlist(int)  # 定义数据类型为int
    15 n.append(123543)
    16 print(n)

    6.组合

    组合是一种关系,描述两个对象之间有什么关系.将一个对象作为另一个对象的属性

      组合一般都是在初始化方法时定义另一个对象

    组合的目的:为了重用现有代码,提高代码的重用性

    组合的例子

     1 # 组合:一个类作为另一个类的属性,两者没有关联
     2 # 定义一个英雄类
     3 class Hero:
     4     def __init__(self,name,ad,hp,weapon):
     5         self.name = name
     6         self.ad = ad
     7         self.hp = hp
     8         self.weapon = weapon  # 英雄类和武器类没有关联,想要英雄类使用武器类,必须在初始化时就增加一个武器的属性
     9     # def attack(self,enemy):
    10     #     enemy.hp -= self.ad
    11     #     print('%s攻击了%s,掉了%s血,血量还剩%s'%(self.name,enemy.name,self.ad,enemy.hp))
    12 
    13 # 定义一个武器类
    14 class Weapon:
    15     def __init__(self,name,att):
    16         self.name = name
    17         self.att = att
    18 
    19     def weapon(self,hero,enemy):
    20         enemy.hp -= self.att
    21         print('%s使用了%s攻击了%s,掉了%s血,血量还剩%s' % (hero.name,self.name,enemy.name, self.att, enemy.hp))
    22 
    23 w1 = Weapon('无尽之刃',100)  # 定义一把武器
    24 h1 = Hero('亚索',50,500,w1)  # 定义一个攻击者
    25 h2 = Hero('提莫',20,400,w1)  # 定义一个敌人
    26 
    27 h1.weapon.weapon(h1,h2)  # 英雄用武器攻击了另一个英雄

    什么时候使用继承:一个类是否包含了另一个类,即什么是什么的关系

    什么时候使用组合:两个类的关联不大,即什么有什么的关系

     

    7.多继承的问题:菱形继承(了解)

    新式类和经典类

    新式类:任何直接或者间接的继承于object的类就称之为新式类.(python3中的类的顶部都是object,所以python3中全是新式类)

    经典类:不是object的子类,只有python2中有

    新式类的继承顺序,先深度遍历,当遇到共同的父类时就广度遍历

    新式类的继承顺序还可以通过调用mro方法来查看

     1 # 定义类
     2 class A:
     3     pass
     4 
     5 class B:
     6     pass
     7 
     8 class C(A):
     9     pass
    10 
    11 class D(A):
    12     pass
    13 
    14 class E(B):
    15     pass
    16 
    17 class F(C):
    18     pass
    19 
    20 class G(D):
    21     pass
    22 
    23 class H(E,F,G):
    24     pass
    25 
    26 print(H.mro())

    新式类的继承顺序:H---->E---->B---->F---->C---->G---->D---->A

    经典类的继承顺序,全部都是深度遍历

     

     经典类的继承顺序:H---->E---->B---->F---->C---->A---->G---->D

     21

  • 相关阅读:
    AQS笔记二 ---- 使用AQS自定义锁
    AQS笔记一 --- 源码分析
    ElasticSearch(二十一)正排和倒排索引
    ElasticSearch(二十)定位不合法的搜索及其原因
    ElasticSearch(十八)初识分词器
    ElasticSearch(十七)初识倒排索引
    还在用 kill -9 停机?这才是最优雅的姿势(转)
    一文快速搞懂MySQL InnoDB事务ACID实现原理(转)
    你真的理解零拷贝了吗?(转)
    关于分布式事务的读书笔记
  • 原文地址:https://www.cnblogs.com/sxchen/p/11247659.html
Copyright © 2020-2023  润新知