4.19Day24类的继承,继承的用法

复习

1、类

对象属性的查找顺序:先找自身再找类
   1.类的名称空间:直接写在类中
   2.对象的名称空间:写在__init__方法中,通过 self.属性 形成名称空间中的名字
   3.类的方法:在类中用@classmethod装饰的方法,第一个参数一定接受类,建议只拿类来调用
   4.对象方法:在类中定义的普通方法,第一个参数一定接受对象,建议只拿对象来调用

2、封装

封装:对外隐藏属性与方法的实现细节,类的内部均可直接访问 __名字
方式:在属性或方法前用 __修饰,将 __名字 更名为 _类__名字
作用:有些属性或方法只提供给内部使用,所以采用封装处理

对象属性的封装,对外提供访问接口:
@property
def id(self):
   return self.__id

@id.seter
def id(self, id):
   self.__id = id
   
@id.deleter
def id(self):
   del self.__id
   
接口原理:
def calssmethod(fn):
   def inner(*args, **kwargs):
       t = args[0]
       args[0] = t.__class__
return inner


class A:
   # 类名()调用的就是__init__方法,调用时传入的实参与形参个数要一致
   # self就是被实例化出来的对象
   def __init__(self, id, name, age):
       self.__id = id
       self.name = name
       self.age = age

今日内容

组合:自定义类的的对象作为类的属性
继承:父类与子类,多继承
接口: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中所定义的所有类

 

posted @ 2019-04-19 18:23  输诚  阅读(111)  评论(0编辑  收藏  举报