一、什么是继承?
继承是一种关系,描述两个对象之间,什么是什么的关系:
新建的类可以继承一个或多个父类,父类有被称为基类或超类,新建的类型称为派生类或子类,在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)
当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度 ,新式类,就是深度优先
继承面试题:
class Init(object):
def __init__(self, v):
print("init")
self.val = v
class Add2(Init):
def __init__(self, val):
print("Add2")
super(Add2, self).__init__(val)
print(self.val)
self.val += 2
class Mult(Init):
def __init__(self, val):
print("Mult")
super(Mult, self).__init__(val)
self.val *= 5
class HaHa(Init):
def __init__(self, val):
print("哈哈")
super(HaHa, self).__init__(val)
self.val /= 5
class Pro(Add2,Mult,HaHa): #
pass
class Incr(Pro):
def __init__(self, val):
super(Incr, self).__init__(val)
self.val+= 1
# Incr Pro Add2 Mult HaHa Init
p = Incr(5)
print(p.val)
c = Add2(2)
print(c.val)