一、继承与派生
1.什么是继承
继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类
继承的特性是:子类会遗传父亲的属性
强调:继承是类与类之间的关系
2.为什么用继承
继承的好处就是可以减少代码的冗余
3.如何用继承
在python中支持一个类同时继承多个父类
在python3中:
如果一个类没有继承任何类,那默认继承object类
在python2中:
如果一个类没有继承任何类,不会继承object类
新式类:
单凡继承了object的类以及该类的子类,都是新式类
经典类:
没有继承object的类以及该类的子类,都是经典类
在python3中都是新式类,只有在python2中才区别新式类与经典类
class Parent1(object):
pass
class Parent2(object):
pass
class Sub1(Parent1,Parent2):
pass
# print(Sub1.__bases__)
print(Parent1.__bases__)
print(Parent2.__bases__)
二、继承的应用
#派生:子类中新定义的属性,子类在使用时始终以自己的为准
class OldboyPeople:
school = 'oldboy'
def __init__(self,name,age,sex):
self.name = name #tea1.name='egon'
self.age = age #tea1.age=18
self.sex = sex #tea1.sex='male'
class OldboyStudent(OldboyPeople):
def choose_course(self):
print('%s is choosing course' %self.name)
class OldboyTeacher(OldboyPeople):
# tea1,'egon',18,'male',10
def __init__(self,name,age,sex,level):
# self.name=name
# self.age=age
# self.sex=sex
OldboyPeople.__init__(self,name,age,sex) #指名道姓访问某一个类的函数
self.level=level
def score(self,stu_obj,num):
print('%s is scoring' %self.name)
stu_obj.score=num
stu1=OldboyStudent('耗哥',18,'male')
tea1=OldboyTeacher('egon',18,'male',10)
#对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
# print(stu1.school)
# print(tea1.school)
# print(stu1.__dict__)
# print(tea1.__dict__)
tea1.score(stu1,99)
print(stu1.__dict__)
# 在子类派生出的新功能中重用父类功能的方式有两种:
#1、指名道姓访问某一个类的函数:该方式与继承无关
小练习:
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1()
class Bar(Foo):
def f1(self):
print('Bar.f1')
#对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
obj=Bar()
obj.f2()
'''
Foo.f2
Bar.f1
'''
三、组合
1.什么是组合
组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象
2.为何用组合
组合也是用来解决类与类之间代码冗余问题的
3.如何用组合
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
def tell_info(self):
msg = '''
课程名:%s
课程周期:%s
课程价钱:%s
''' % (self.name, self.period, self.price)
print(msg)
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex,stu_id):
OldboyPeople.__init__(self, name, age, sex)
self.stu_id = stu_id
def choose_course(self):
print('%s is choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self, name, age, sex, level):
OldboyPeople.__init__(self, name, age, sex)
self.level = level
def score(self, stu, num):
stu.score = num
print('老师[%s]为学生[%s]打分[%s]' % (self.name, stu.name, num))
#创造课程
python=Course('python全栈开发','5mons',3000)
linux=Course('linux运维','5mons',800)
#创造学生与老师
stu1=OldboyStudent('猪哥',19,'male',1)
tea1=OldboyTeacher('egon',18,'male',10)
#将学生、老师与课程对象关联/组合
stu1.course=python
tea1.course=linux
stu1.course.tell_info()
tea1.course.tell_info()
#定义一个学生类为了得到学生对象 , 定义一个课程类为了得到课程对象,刚开始两者没关系
我让学生对象具备某一个属性,而这个属性的值来自另外一个类。stu1.course定位到课程类对象。
stu1的课程属性是属于学生对象属性,这个属性来自另外一个类,就可以用stu1.course.可以用到左侧
对象,类的所有东西
四、菱形继承问题
1.菱形继承:
当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承
2.菱形继承的问题:
python2区分经典类与新式类,如果子的继承是一个菱形,那么经典类与形式的区别为?
经典类下查找属性:深度优先查找
新式类下查找属性:广度优先查找
class G(object):
# def test(self):
# print('from G')
pass
class E(G):
# def test(self):
# print('from E')
pass
class B(E):
# def test(self):
# print('from B')
pass
class F(G):
# def test(self):
# print('from F')
pass
class C(F):
# def test(self):
# print('from C')
pass
class D(G):
# def test(self):
# print('from D')
pass
class A(B,C,D):
def test(self):
print('from A')
# pass
obj=A()
print(A.mro())
# obj.test() #A->B->E-C-F-D->G-object
继承原理(C3算法与mro)继承原理 MRO列表就是一个简单的所有基类的线性顺序列表
五、在子派生的新方法中重用父类功能的两种方式
方式一:
指名道姓法,直接用:类名.函数名
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, stu_id):
OldboyPeople.__init__(self, name, age, sex)
self.stu_id = stu_id
def choose_course(self):
print('%s is choosing course' % self.name)
方式二:
严格依赖继承属性查找关系
super()会得到一个特殊对象,该对象就是专门用来访问父类中的属性(按照继承关系)
super().__init__(不用为self传值)
注意:
super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以写super()
强调:二者使用哪一种都可以,但最好不要混合使用
lass OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, stu_id):
super().__init__(name,age,sex) ######
# OldboyPeople.__init__(self, name, age, sex)
self.stu_id = stu_id
def choose_course(self):
print('%s is choosing course' % self.name)
stu1=OldboyStudent('egon',19,'male',10)
print(stu1.__dict__)
小练习:
class A:
def f1(self):
print('A.f1')
class B:
def f2(self):
super().f1()
print('B.f2')
class C(B, A):
pass
obj=C()
obj.f2()
print(C.mro()) # C->B->A->object B没有继承A,但super会基于C.mro()继续往后找
super严格依赖继承关系,从当前类的下一个类开始查找
# A.f1
B.f2
六、多态与多态性
1.什么是多态
多态指的是同一种事物的多种状态
水--》冰、水蒸气、液态水
动物——》人、狗、猪
2.为什么用多态
多态性:继承同一个类的多个子类有相同的方法名
那么子类产生的对象就可以不用考虑具体类型而直接调用功能
3.如何用
动物多态:
import abc #abc=abstract class
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self):
pass
@abc.abstractmethod
def eat(self):
pass
# Animal() #强调:父类是用来指定标准的,不能被实例化
class People(Animal):
def speak(self):
print('say hello')
def eat(self):
pass
class Dog(Animal):
def speak(self):
print('汪汪汪')
def eat(self):
pass
class Pig(Animal):
def speak(self):
print('哼哼哼')
def eat(self):
pass
python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
多态性是指在不考虑实例类型情况下使用实例
class Disk:
def read(self):
print('disk read')
def write(self):
print('disk wirte')
class Process:
def read(self):
print('process read')
def write(self):
print('process wirte')
class File:
def read(self):
print('file read')
def write(self):
print('file wirte')