4.19Day24类的继承,继承的用法
1、类
对象属性的查找顺序:先找自身再找类
1.类的名称空间:直接写在类中
2.对象的名称空间:写在__init__方法中,通过 self.属性 形成名称空间中的名字
3.类的方法:在类中用@classmethod装饰的方法,第一个参数一定接受类,建议只拿类来调用
4.对象方法:在类中定义的普通方法,第一个参数一定接受对象,建议只拿对象来调用
2、封装
封装:对外隐藏属性与方法的实现细节,类的内部均可直接访问 __名字
方式:在属性或方法前用 __修饰,将 __名字 更名为 _类__名字
作用:有些属性或方法只提供给内部使用,所以采用封装处理
对象属性的封装,对外提供访问接口:
今日内容
组合:自定义类的的对象作为类的属性
继承:父类与子类,多继承
接口:python中没有接口的语法,接口是一种编程思想
抽象类:abc(元类的思想)
多态:继承法师的多态,鸭子类型
组合
概念:自定义类的对象作为另一个类的属性
示例:
# 定义一个老师类
class Teacher:
def __init__(self, name, age):
self.name = name
self.age = age
# 定义一个学生类
class Student:
# 学生得有 老师 属性(特征属性)
def __init__(self, name, age, teacher):
self.name = name
self.age = age
self.teacher = teacher # ==>以 老师 对象作为属性传入学生的属性
# 创建一个老师
t1 = Teacher('Egon', 18)
# 创建一个学生
stu = Student('Wjw', 22, t1) # ==>以 老师 对象作为属性传入学生的属性
测试:
print(stu.name) # Wjw
print(stu.teacher) # <__main__.Teacher object at 0x00000000024E78D0>
# 利用 stu.teacher.老师的属性 来访问到老师的属性
print(stu.teacher.name) # Egon
print(stu.teacher.age) # 18
继承
子类 | 父类
子类可以访问父类的 属性与功能
将所有共有的属性与方法抽离出,形成父类
父类 是多个有共同点的普通类 抽离出的共有属性与方法 形成的 类
示例:
# 学生类
class Student:
identify = '学生'
def __init__(self, name):
self.name = name
def eat(self):
print('[%s]正在吃饭...' % self)
# 老师类
class Teacher:
def __init__(self, name):
self.name = name
def eat(self):
print('[%s]正在吃饭...' % self)
#领导类
class Leader:
def __init__(self, name):
self.name = name
def eat(self):
print('[%s]正在吃饭...')
通过观察,发现学生、老师、领导类中有相同的属性与功能
类与类之间有大量的代码冗余
可以通过 类 继承 的特性 来将代码优化,减少代码冗余
继承的语法:
class 类名(父类名):pass
所以我们可以将 相同的属性与功能 抽离成一个父类:
# 父类
class People: # 父类名要对相同的 属性与功能 有一定的描述意义
# 相同的冗余代码
def __init__(self, name):
self.name = name
def eat(self):
print('[%s]正在吃饭...' % self)
# 子类
class Student(People):
identify = '学生' # 此为学生类的特有属性,故不抽离为父类属性
student = Student('Zdc')
student.eat() # [Zdc]正在吃饭...
# 子类
class Teacher(People):
pass
teacher = Teacher('Wjw')
teacher.eat() # [Wjw]正在吃饭...
# 子类
class Leader(People):
pass
leader = Leader('Cao')
leader.eat() # [Cao]正在吃饭...
print(Student.identify) # 自身类拥有identify属性
print(Teacher.identify) # 自身没有identify属性,父类也没有,其他类就没有
print(Leader.identify) # 自身没有identify属性,父类也没有,其他类就没有
继承信息
继承中 子类 访问 父类 时的 访问权限:
继承关系
1.父类的所有未封装的属性和方法,子类都能访问
2.父类的所有封装的属性和方法,子类都不能访问
-- 在外界通过子类或子类对象,不能访问
-- 在子类内部也不能访问
方法的重写
在继承关系下的属性查找顺序:
1、优先找自身,自身没有找父类
2、父类没有找父类的父类
3、一直找到最顶级的父类(最顶级的父类到底其实是object),如果还没有就报错
两个名词:
先定义子类:抽离 出 父类
先定义父类:派生 出 子类
查找关系示例:
class Sup:
num = 10
def test(self):
print('test Sup')
class Sub:
num = 100
def test(self):
print('test Sub')
print(Sub.num) # 100
Sub.test() # test sub ## 并没有访问到父类的test方法
方法的重用
重用:需要用到父类的功能,但是需要增加上自己需求的新功能
方法:在子类中父类的方法,调用者必须是子类(或子类的对象)
最基础 方法的重用:
示例:
class Sup:
def test(self):
print('>>>sup', self)
print('test sup')
class Sub:
def test(self):
# 直接调用父类中的test方法
# 此方法过于繁琐,有简化写法
# Sup().test()
# python3中简化写法
super().test()
# python2中写法
Sup(Sub,self).test()
print('>>>sub', self)
print('test sub')
# 调用子类中 重用父类方法的test方法
Sub().test()
run==>
>>>sup <__main__.Sup object at 0x00000000023EC0B8>
test sup
>>>sub <__main__.Sub object at 0x00000000023EC4E0>
test sub
用__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 # 指名道姓调用父类的test方法
print(num)
# 默认父级的__init__可以被继承过来
# 但是会出现子类对象的属性比父类多
def __init__(self, name, salary):
super().__init__(name)
self.salary = salary
# 创建一个子类对象
s1 = Sub('egon', 18)
Sub().test(10)
run==>
<__main__.Sub object at 0x00000000004BC2B0> # 子类中test方法 的内存地址
10
Sub().test() # 报错:test方法少1个参数; 这就证明调用的是自身的test方法
# test方法名字相同,本质上就只有一个test方法,优先查找自己的,自己没有也不会再去找父类的
多继承
简单的多继承:
属性的查找顺序:优先找自己的,如果灭有,按照继承先后查找父级
class A:
name = 'A'
num = 10
class B:
name = 'B'
count = 100
# 子类可以继承所有父类可继承的属性
class C(A, B): # 查找顺序: 自己 => A => B
pass
# 打印属性查找顺序的语法
print(C.mro()) # 查找类C的属性查找顺序
复杂的多继承:
class A:
name = "A"
class B(A):
name = "B"
class C:
name = "C"
class D(C):
name = "D"
class E(B, D):
name = "E"
print(E.mro())
# 经典类:python2中才有经典类,就是没有继承任何类的类
# (python2中最终层不会默认给类创建object父类)
# 新式类:python2中需要直接或间接继承object的类,python中所定义的所有类