面向对象特性之 继承
目录
面向对象三大特性
继承
封装
多态
继承
一、什么是继承
继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。父类的属性和方法,子类中也有。
格式就是子类名加括号,括号内是父类名:
class A:
pass
class B(A): # B就继承了A
pass
这里提一下新式类和经典类的区别
新式类:只要继承了object类,就是新式类,在python3中,默认都是新式类
在python2中,需要显示指定继承object才是新式类
经典类:在python2中,没有继承object的类,就是经典类
python3中没有经典类
二、类的继承分为单继承和多继承
class A(object):
pass
class B(A):
pass
# B继承了A这个类,单继承
class C(A,B):
pass
# C继承了A和B,多继承
类的其他内置属性:__名字__
print(B.__dict__) # 类的属性和方法
print(B.__name__) # 类名
print(B.__bases__) # 类的父类
继承中属性的查找顺序:
先在对象中找---》子类中找---》父类中找(多继承父类的话,从左到右,先从第一个父类找)---》父类中找不到就报错
三、利用继承减少代码冗余
# 这里首先利用面向对象写一个老师和学生的类,他们的基类都是人
# 这里不用继承
class Person:
school = 'oldboy'
class Teacher(Person):
def __init__(self,name,age,level):
self.name=name
self.age=age
self.level=level
class Student(Person):
def __init__(self,name,age,course):
self.name=name
self.age=age
self.course=course
# 以上代码老师和学生的类都有共同属性:name和age,那就可以把这两个属性放到人的类中,然后老师和学生的类来继承人的类
class Person(object):
school = 'oldboy'
def __init__(self, name, age):
self.name = name
self.age = age
class Teacher(Person):
pass
class Student(Person):
pass
# 这样就减少了代码的冗余
注意:子类实例化会自动调用__init__
方法,如果子类中没有,会去父类中找,父类中有几个参数就要传几个参数
四、多层继承和多继承
# 多层继承:一层一层的继承下去
class A:
a="AAAA"
class B(A):
a="BBB"
class C(B):
a="CCC"
pass
class D(C):
a = "DDD"
pass
# 多继承
class A:
a="AAAA"
class B:
a="BBB"
class C:
a="CCC"
pass
class D(A,B,C): # 类 D 继承了上面多个类
a = "DDD"
pass
# 多继承的多层
class A:
a="AAAA"
class B(A):
a="BBB"
class C(B):
a="CCC"
pass
class D(A,B,C):
a = "DDD"
pass
五、继承属性查找顺序
5.1 菱形问题
继承的菱形问题(显示的都继承一个类,不是object类):新式类和经典类的查找顺序是不一样的。
新式类(py3中全是新式类):广度优先---从左侧开始,一直往上找,找到菱形的顶点结束(不包括菱形顶点),继续下一个继承的父类往上找,找到菱形的顶点结束(不包括菱形顶点),最后找到菱形顶点。
经典类(只有py2中才有):深度优先---从左侧开始,一直往上找,找到菱形的顶点结束(包括菱形顶点)继续下一个继承的父类往上找,找到菱形的顶点结束(不包含菱形定点)。
不出现菱形问题:正常查找
#继承的菱形问题:新式类和经典类的查找顺序是不一样的
#新式类的查找属性:广度优先
#经典类:深度优先
class G(object):
a = "GGG"
pass
class F(G):
# a = "FFF"
pass
class E(G):
# a = "EEE"
pass
class D(G):
# a = "DDD"
pass
class C(F):
# a="CCC"
pass
class B(E):
# a="BBB"
pass
class A(B,C,D):
# a="AAAA"
pass
a=A()
print(a.a)
以上代码就出现新式类的菱形问题,查找顺序就是广度优先:
经典类的菱形问题,查找顺序就是深度优先:
5.2 根据mro
列表查找
mro:列表,继承顺序查找列表(只在新式类中有)
print(A.mro())
print(A.__mro__)
# 两种方式都可以
六、继承重用父类方法得两种方式
6.1 方式一:指名道姓的使用,跟继承关系无关
# 父类中object写与不写,在py3中没有区别,
# 有的人在py3中这么写,为了向下兼容
# 调用父类方法的第一种方式 :指名道姓的方式,跟继承关系无关
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def init_1(self,name,age):
self.name=name
self.age=age
class Student:
school = 'yyyy'
def __init__(self,name,age,course):
Person.__init__(self,name,age) #指名道姓的使用Person的__init__方法,Preson中有三个参数就必须传三个
init_1(self,name,age)
self.course=course
stu=Student('nick',19,'python')
print(stu.name)
6.2 方式二:通过super关键字,跟继承关系有关
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
class Student(Person):
school = 'yyyy'
def __init__(self,name,age,course):
#super()相当于得到了一个特殊对象,第一个参数不需要传,调用绑定方法,会把自己传过去
########## self不需要传,不需要传
super().__init__(name,age)
#看到别人这么写:super(类名,对象) 在py3中为了兼容py2
#在py3中这么写和省略写法完全一样
#在py2中必须super(Student,self)写
# super(Student,self).__init__(name,age)
self.course=course
stu=Student('nick',19,'python')
print(stu.name)
print(stu.age)
print(stu.course)
6.3 总结
有继承关系的时候,通常用super关键字方法;
指名道姓的方法在以下情况下用:
- 没有继承关系
- 如果继承了多个父类,super是按照mro列表找,现在想指名道姓的用某个父类的某个方法,就需要指名道姓的使用