继承
复习
1.类
对象属性的查找循序,先找自身再找类
1.类的名称空间:直接写在类中
2.对象的名称空间:写在__init__方法中,第一个参数一定接收类,建议只拿类来调用
3.类的方法:在类中用@classmethod装饰的方法,第一个参数一定接受类,建议只拿类来调用
4.对象方法:在类中定义的普通方法,第一个参数一定接收对象,建议只拿对象调用
2.封装
封装:对外隐藏属性与方法的实现细节,类的内部均可以直接访问__名字
方式:在属性或方法前用__装饰,将__名字更名为_类__名字
作用:有些属性或方法只提供给内部使用,所有采用封装处理
对象属性的封装,对外提供接口
装饰器classmethod的本质就是
def classmethod(fn)
def inner(*args,**kwargs)
t=args[0]
args[0] = t.__class__
pass
return inner
3.组合
组合的本质就是自定义类的对象作为另一个类的属性
class Teacher:
def __init__(self, name, age):
self.name = name
self.age = age
t1 = Teacher("Owen", 17)
print(type(t1.name), type(t1.age))
class Student:
# 学生可以有 老师 属性
def __init__(self, name, age, teacher):
self.name = name
self.age = age
# 自定义类的对象作为类的属性:组合
self.teacher = teacher
# 创建一个学生
stu = Student('Bob', 18, t1)
print(stu.__dict__)
# 学生的老师年龄和姓名
print(stu.name)
print(stu.teacher)
print(stu.teacher.name)
print(stu.teacher.age)
4.继承
将所有的属性与方法抽离出,形成父类
父类是多个有共同点的普通类抽离共有属性和方法形成的类
class People
def __init__(self,name)
self.name = name
def eat(self)
print(self.name + '在吃饭')
class Student(People)
identify = '学生'
student=Student('Bob')
student.eat()
Student继承父类People的属性和方法,但是也可以有自己独有的属性或方法,如identify
#继承关系
1.父类的所有未封装的属性和方法,子类都能访问
2.父类的所有封装的属性和方法,子类都不能访问
————在外界通过子类或子类对象,也不能访问
————在子类内部也不能访问
#继承关系下的属性查找顺序
1.优先找自身,自身没有找父类
2.分类没有找父类的父类
3.一直找到最顶级的父类,如果还没有就报错。
#两个名词
抽离:先写子类抽离出父类
派生:先写父类派生出子类
# 方法的重写
先写好父类的方法,由于父类方法的功能不能满足子类要求,子类就可以重写父类方法。
重写方法:方法名与父类相同,自定义方法的实现体。(其实就是优先于父级访问自身同名的方法)
class Sup:
num = 10
def test(self):
print('test sup')
class Sub(Sup):
def test(self):
print('test sub')
Sub().test()
#方法的重用
重用:还需要父类方法的功能,在父类方法功能基础上添加新功能
突破点:在子类中调用父类的方法,还有保证调用者就是子类(子类的对象)
#针对类中普通的方法
#方法一:super
class Sup:
def test(self):
print('>>>sup', self)
print('test sup')
class Sub(Sup):
pass
def test(self):
# Sup().test()
# python2中写法
# super(Sub, self).test()
# python3中简化写法
super().test()
print('>>>sub', self)
print('test sub')
Sub().test()
#方法二,直接调用,与继承没有关系,同样使用对象的绑定
class Sup:
def test(self):
print('>>>sup', self)
print('test sup')
class Sub(Sup):
pass
def test(self):
Sup.test(self)
print('>>>sub', self)
print('test sub')
Sub().test()
#================针对类中的__init__方法==================
以上面相同,有两种
#方法一、super
人类:只需要初始化 - name
老师: 要初始化 - name salary
学生: 要初始化 - name grade
class Sup:
def test(self):
print(self)
def __init__(self,name)
self.name = name
class Sub(Sup)
#有继承关系下,只要名字相同,即时产生不同,还是属于同一个方法
def test(self,num)
super().test()
print(num)
#默认父级的__init__可以被继承过来
#但是会被出现子类对象的属性比父类多
def __init__(self,name,salary)
super().__init__(name)#父级有的共性功能能通过super()交给父级做
self.salary = salary#子类特有的自己来完成
#方法二,直接调用
class Sup:
def test(self):
print(self)
def __init__(self, name):
self.name = name
class Sub(Sup):
def test(self, num):
Sup.test(self)
print(num)
def __init__(self, name, salary):
Sup.__init__(self,name)
self.salary = salary
多继承
经典类:没有继承任何类的类(python2中存在,因为没有像python3一样,当没有父级时默认object为父级。)
新式类:python2中要直接或间接继承object的类,而python3中所定义的所有类都是新式类(默认最高级是父级)
经典类:深度查找,就是查找到最高级后,再去广度查找
新式类:广度查找,广度自左向右查询结束后,再去查最高级,其实依照MRO列表中的顺序自左向右查询(只有在新式类找那个有)