面向对象的三大特性之一:继承

一、什么是继承?

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

新建的类可以继承一个或多个父类,父类有被称为基类或超类,新建的类型称为派生类或子类,在python中有单继承和多继承

class Base:
    ser="这是一个基类"
    def show_info(self):
        print(self.ser)

    def make_money(self):
        print("哎!苦逼的一天")
        # 指定父类位Base

class Subclass(Base):
    pass
obj=Subclass() # 即使类中什么都没有也可以使用父集中已经有的内容
obj.make_money()
print(obj.ser)

  在程序中,继承描述的是类和类之间的关系,例如:a继承了b,a就能直接使用b已经存在的方法和属性

查看继承:

print(Subclass.__bases__)

二、抽象与继承:抽象就是不清晰、不具体、很迷糊
  抽象即抽取类似或者说比较像的部分:将人,猪,狗这三个类比较像的部分抽取成父类。 动物
 正确的使用继承:
  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): #  调用 使代码的重复性降低
    # def teaching(self):
        print("老师上课就犯困...!")
t1=Teacher("Json","female",20)
t1.say_hi()

class Student(Person):# 调用同样属性的特征
        pass
stu1=Student("Reso","male",18)
stu1.say_hi()


“子类调用了父类的同样年龄、姓名、性别的属性,使得代码没有那么重复”

三、派生

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

通常子类都会写一些新的代码,不可能和父类完全一致,即通常都是派生类,所以派生类指的就是子类

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

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

stu = Student()
stu.say_hi()

四、覆盖:

  也称之为重写:overrides 当子类出现了与父类名称完全一致的属性或方法

  根据查找顺序,优先使用子类中的属性,这种行为也称为覆盖

五、属性的查找顺序:

  对象自己的-->>所在的类中->>找父类->>父类的父类->>Object(对象)

class A:
    text="heihei"
class B(A):
    text="haha"
class C(B):
    text="dogdog"
    pass
b=B()
b.text="are you ok"
print(b.text)

c=C()
c.text="aabb"
print(c.text)

>>

are you ok
aabb

六、子类访问父类的内容 

  语法:调用super()

方式1:
super(当前类名称,self).你要调的父类的属性或方法
方式2:
super().你要调的父类的属性或方法 # 访问方式2 py3的新语法 最常用的方式
方式3: 类名称.你要调的父类的属性或方法(self) 

#方式3与继承无关
class Parent:
    text = "abc"
    def say_something(self):
        print("anything")
class Sub(Parent):
    def show_info(self):
        # print(super(Sub,self).text)
        # super(Sub,self).say_something()
        # 访问方式2  py3的新语法 最常用的方式
        print(super().text)
        super().say_something()
        #方式3 直接指定类名调用
        # print(Parent.text)
        # Parent.say_something(self)
sub = Sub()
sub.show_info()


>>>
    why?

重点:

  当你要继承一个出现有的类,并覆盖了父类的__init__的方法时,必须在初始化方法的第一行调用父类

的初始化,并传入父类所需的参数( 应用的场景是需要有特定的限制条件时 )

class Student(Person):

def __init__(self,name,gender,age,number):
super().__init__(name,gender,age) # 类的属性中有多余的number 使用前必须先定义
self.number= number

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

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")

   当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。如果每个重定义的方法统一使用super()并只调用它一次,

那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次

(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:
    def test(self):
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
c.test() #打印结果:from B


print(C.mro())
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

七、组合:

  指的是:在一个类中以另外一个类的对象做为数据属性称为类的组合

  例如:学生有手机,游戏中角色拥有某些技能(即有什么有什么)

组合的目的: 也是重用现有的代码

什么时候使用继承:分析两个类的关系,到底是不是:什么是什么的关系

什么时候使用组合:如果两个类之间 没有太大的关系,完全不属于同类

八、菱形继承:

补充:新式类与经典类

python3中任何类都是直接或间接继承了Object

新式类,任何显式或隐式地继承自object的类就称之为新式类, python3中全都是新式类 

经典类,既不是Object的子类 ,仅在python2中出现 

菱形继承
class A:
    j = 1
    pass

class B:
    # j = 2
    pass

class C(A):
    # j = 3
    pass

class D(A):
    j = 4
    pass

class E(B,C,D):
    # j = 5
    pass

d = E()
print(d.j)

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

新式类,就是深度优先

  




  


 

猜你喜欢

转载自www.cnblogs.com/Gaimo/p/11247426.html