面向对象的三大特性之一:继承
Posted Jeremy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象的三大特性之一:继承相关的知识,希望对你有一定的参考价值。
一、什么是继承?
继承是一种关系,描述两个对象之间,什么是什么的关系:
新建的类可以继承一个或多个父类,父类有被称为基类或超类,新建的类型称为派生类或子类,在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)
当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度
新式类,就是深度优先
以上是关于面向对象的三大特性之一:继承的主要内容,如果未能解决你的问题,请参考以下文章