OPP三大特性之继承

一、继承基本知识

1.什么是继承

继承是一种关系,描述两个对象之间,什么是什么的关系

在程序中,继承描述的是类与类之间的关系

例如a继承了b,a就能直接使用b已将存在的方法和属性

a称之为子类,b称之为父类,也称之为基类

 

2.为什么要使用继承

继承的一方可以直接使用被继承一方已经有的东西

其目的可以减少代码冗余,提高重用性

 

3.如何使用继承

class Base:
    desc = "这是一个基类"

    def show_info(self):
        print(self.desc)

    def make_money(self):
        print("一天赚一个亿...")


class SubClass(Base):  # 子类为SubClass,它的父类为Base
    pass


obj = SubClass()
#即使类中什么都没有也可以使用父类中已有的内容
obj.make_money()  # 一天赚一个亿...
print(obj.desc)  # 这是一个基类

 

二、抽象

1.定义:

将多个子类中相同的部分,进行抽取,形成一个新的类,这个过程称之为抽象过程

2.正确的使用继承

先抽象在继承

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

抽取老师和学生中相同的部分形成person类

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def say_hi(self):
        print("name:%s,gender:%s,age:%s" % (self.name,self.gender,self.age))


class Teacher(Person):  # 子类Teacher从父类Person中进行取值
    def teaching(self):
        print("老师教学生,写代码....")


t1 = Teacher("jack","male",20)
t1.say_hi()  # name:jack,gender:20,age:male


class  Student(Person):
    pass

stu1 = Student("rose","female",18)
stu1.say_hi()  # name:rose,gender:18,age:female

 

三、属性的查找顺序

一个类必然继承另一个类,被继承的类也有可能继承了其他类,相当于C继承B,B又继承A

class A:
    text = "haha"

class B(A):  # B的父类是A
    text = "heihei"
    pass

b = B()  # B中有自己的属性
# b.text = "xixi"  # 如果这个值注释掉,那么它就会找自己所在的类,那么值就会是heihei

print(b.text)  # xixi

查找顺序:

对象本身的名称空间 - > 类的名称空间 -> 父类的名称空间 -> 父类的父类名称空间 ->...object类

会沿着继承关系一直往后查找,直到找到为止,由于object是所有类的根类,所以如果找不着最后都会查找object类!

 

四、派生

当一个子类中出现了与父类中不同的内容时,这个子类就称之为派生类

通常子类都会写一写新代码,不可能和父类完全一样,即通常都是派生类,

所以派生类指的就是子类

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print('爹的f1')

class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,level,salary):
        self.name=name
        self.age=age
        self.sex=sex

        self.level=level
        self.salary=salary

    def change_score(self):
        print('teacher %s is changing score' %self.name)

    def f1(self):
        print('儿子的f1')

tea1 = OldboyTeacher('egon', 18, 'male',9,3.1)
print(tea1.name,tea1.age,tea1.sex,tea1.level,tea1.salary)

 

五、覆盖

也称之为重写

在子类中如果出现与父类相同的属性名称时,根据查找顺序,

优先使用子类中的属性

class Person:
    def say_hi(self):
        print("hello")



class Student(Person):
    def say_hi(self):
        print("hello world!")


stu = Student()
stu.say_hi()  # hello world!

 

练习

需求 实现一个能够限制元素类型的列表类

**class MyList(list):**
    **def init(self,element_type):**
        **super().init() # 调用父类的初始化方法 来完成基本的初始化**
        **self.element_type = element_type**

```
def append(self, object):
    """
    :param object: 是要存储的元素
    :return: 没有
    """
    if type(object) == self.element_type:
        #我们需要在这里访问父类的append函数来完成真正的存储操作
        super(MyList,self).append(object)
    else:
        print("sorry sir, you element type not is %s" % self.element_type)
```

创建是指定要存储的元素类型

m = MyList(int)

当你有需求,是需要在创建对象时 干点什么事儿  那就该想到初始化方法

m.append(1)
print(m[0])
m.append("121212")
View Code

 

六、子类访问父类中的内容

方式一:指名道姓地调用(其实与继承没有什么关系的)

直接调用父类当中的属性,减少代码冗余

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))


class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level, salary):

        OldboyPeople.__init__(self,name, age, sex)

        self.level = level
        self.salary = salary

    def tell_info(self):
        OldboyPeople.tell_info(self)
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)


tea1.tell_info()

 

方式二:super()调用(严格依赖于继承)

uper()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性

了解:在python2中,需要super(自己的类名,self)

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))


class OldboyTeacher(OldboyPeople):
 
    def __init__(self, name, age, sex, level, salary):
        
        super(OldboyTeacher,self).__init__(name,age,sex)

        self.level = level
        self.salary = salary

    def tell_info(self):
      
        super().tell_info()
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)

tea1.tell_info()

注意:

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

 

七、组合

定义:

组合是一种关系,描述两个对象之间的互相有什么关系

将一个对象作为另一个对象的属性

组合目的

能够重用现有的代码

class Equip: #武器装备类
     def fire(self):
         print('release Fire skill')

class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
     camp='Noxus'
     def __init__(self,nickname):
         self.nickname=nickname
         self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
r1=Riven('锐雯雯')
r1.equip.fire() #可以使用组合的类产生的对象所持有的方法

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同

1.继承的方式

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

2.组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

 

八、新式类与经典类

1.新式类:

继承object的类,以及该类的子类,都是新式类

在python3中,如果一个类没有指定继承object的父类,默认就继承 所以说python3中所有的类都是新式类

2.经典类(只有在python2才区分经典类与新式类):

没有继承object的类,以及该类的子类,都是经典类

 

九、菱形继承

在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先.

 

 

 

这里谈到的广度优先不是简单的从左到右,像图中标识的依然会按照深度一层一层上找,

但是如果下一个要找的类与继承列表中的其他类存在相同父类(就像EF有共同父类G),

则不会查找公共父类,这一次深度查找结束,开始下一条查找路径(C -> F)

当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度

新式类,就是深度优先

 

 

 

 

经典类查找顺序

posted @ 2019-07-25 22:07  小青年て  阅读(731)  评论(0编辑  收藏  举报