图灵python大海老师面向对象进阶.pdf

继承

1.继承介绍

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

1.1.什么是继承

继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类

python中继承的特点:

子类可以遗传/重用父类的属性

1.2.为何要用继承

减少类与类之间代码冗余

1.3.如何用继承

语法

  1. class 父类:
  2. pass
  3. class 子类(父类):
  4. pass

实例

  1. class Parent1:
  2. xxx = 333
  3. def run(self):
  4. print('我是父类的方法')
  5. class Sub1(Parent1):
  6. # xxx = 222
  7. # def run(self):
  8. # print('我是子类的方法')
  9. pass
  10. obj = Sub1()
  11. # obj.xxx=111
  12. # 对象 << 类 << 父类
  13. print(obj.xxx)
  14. obj.run()

2.利用继承来解决类和类直接的代码冗余问题

我们先思考一个问题:请看图

image.png

1.对象和类的关系

奥巴马和梅西都有人的特征,麦兜和猪坚强都有猪的特征,史努比和史派克都有狗的特征
所以总结对象的相似之处得到了类

2.类和父类的关系

人,猪和狗都有动物的特征
所以总结类的相似之处得到父类

例子

学生类和老师类都是人,所以他们具有人相同的特征

  1. # @Author : 大海
  2. # @File : 2.利用继承来解决类和类之间的代码冗余问题.py
  3. '''
  4. 总结对象的相似之处得到了类
  5. 总结类的相似之处得到父类
  6. '''
  7. class People:
  8. school = '图灵学院'
  9. def __init__(self,name,age,sex):
  10. self.name = name
  11. self.age = age
  12. self.sex = sex
  13. class Student(People):
  14. # def __init__(self,name,age,sex):
  15. # self.name = name
  16. # self.age = age
  17. # self.sex = sex
  18. def play(self):
  19. print('%s play football' % self.name)
  20. class Teacher(People):
  21. # def __init__(self,name,age,sex):
  22. # self.name = name
  23. # self.age = age
  24. # self.sex = sex
  25. def course(self):
  26. print('%s course'%self.name)
  27. # 实例化的时候子类没有__init__方法会调用父类的
  28. stu1 = Student('周阳',30,'male')
  29. print(stu1.__dict__)
  30. tea1 = Teacher('大海',31,'man')
  31. print(tea1.__dict__)
  32. # 但是这里有个问题子类有新的属性需要实例化的时候参数怎么办

继承是一种新建类的方式,新建的类称之为子类/派生类,被继承 的类称之为父类\基类\超类
python中继承的特点: 子类可以遗传/重用父类的属性

总结对象的相似之处得到类,总结类的相似之处得到父类

派生

1.什么是派生

指的是子类继承父类的属性和方法,并且派生出自己独有的属性与方法。

2.为什么要派生

子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找,
例如每个学生还有分数这一属性,我们就需要在Student类中定义该类自己的
init方法去覆盖父类的(因为优先用子类的方法)

子类派生重用父类功能一

子类重用父类的功能,在子类派生出的新方法中重用父类功能的方式一:指名道姓地引用某个类中的函数。

  1. class People:
  2. school='图灵学院'
  3. def __init__(self,name,age,sex):
  4. self.name=name
  5. self.age=age
  6. self.sex=sex
  7. class Student(People): #这里即使没有引用父类,代码也能下常运行
  8. #写个默认参数
  9. def __init__(self,name,age,sex,score=0):
  10. People.__init__(self,name,age,sex) #指明方法 引用并修改
  11. self.score=score
  12. def play(self):
  13. print('%s play football'%self.name)
  14. class Teacher(People): # 子类在父类的基础上添加一个新的形参
  15. def __init__(self,name,age,sex,hoppy):
  16. People.__init__(self,name,age,sex)
  17. self.hoppy=hoppy
  18. def course(self):
  19. print('%s course'%self.name)
  20. stu1=Student('周阳',30,'male')
  21. print(stu1.__dict__)
  22. tea1=Teacher('大海',31,'男','篮球')
  23. print(tea1.__dict__)

子类派生重用父类功能二

派生实例化除了父类的属性添加,还能有自己独有的属性
在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
super(自己的类名,自己的对象)
可以省略传值
super()

  1. class People:
  2. school='图灵学院'
  3. def __init__(self,name,age,sex):
  4. self.name=name
  5. self.age=age
  6. self.sex=sex
  7. class Student(People):
  8. #写个默认参数
  9. def __init__(self,name,age,sex,score=0):
  10. super(Student,self).__init__(name,age,sex)
  11. # 也可省略传值 super().__init__(name,age,sex)
  12. self.score=score

单继承背景下的属性查找

优先级 :对象》对象的类》父类》父类》

4.1.在单继承背景下的属性查找顺序

  1. # @Author : 大海
  2. # @File : 4.在单继承背景下的属性查找.py
  3. # 在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....->object
  4. class Foo():
  5. xxx = 444
  6. pass
  7. class Bar1(Foo):
  8. xxx = 333
  9. pass
  10. class Bar2(Bar1):
  11. xxx = 222
  12. pass
  13. obj = Bar2()
  14. # obj.xxx=111
  15. print(obj.xxx)

例子

  1. class Foo:
  2. def f1(self):
  3. print('Foo.f1')
  4. def f2(self):
  5. print('Foo.f2')
  6. # obj.f1()是Bar()的对象
  7. self.f1()
  8. class Bar(Foo):
  9. def f1(self):
  10. print('Bar.f1')
  11. obj=Bar()
  12. obj.f2()

多继承背景下的属性查找

广度优先查找

image.png

例子

  1. # @Author : 大海
  2. # @File : 5.在多继承背景下的属性查找.py
  3. # 在多继承背景下属性的查找优先级: **
  4. # 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去
  5. # 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
  6. # 第四层 # 顶级类是在最后一个分之才走的
  7. class G():
  8. x = 'G'
  9. pass
  10. # 第三层
  11. class E(G):
  12. # x = 'E'
  13. pass
  14. class F(G):
  15. # x='F'
  16. pass
  17. # 第二层
  18. class B(E):
  19. # x= "B"
  20. pass
  21. class C(F):
  22. # x='C'
  23. pass
  24. class D(G):
  25. # x='D'
  26. pass
  27. # 第一层
  28. class A(B,C,D):
  29. # x = 'A'
  30. pass
  31. obj = A()
  32. # obj.x = 111
  33. print(obj.x)
  34. # python专门为继承类内置了一个mro的方法,用来查看c3算法的计算结果
  35. print(A.mro())

优先级:对象》对象的类》按照从左往右的顺序一个分支一个分支的找下去
广度优先查找,从左往右一个分支一个分支的查找, 在最后一个分支才去查找 顶级 类
在多继承背景下的属性查找

mro方法

python 专门为继承类内置了一个mro的方法,用来查看c3算法的计算结果(查看子类继承属性的优先级)

  1. print(A.mro()) #A为一子类,这里主要展示mro方法格式

组合

组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象

为何使用组合:

通过为某一个对象添加属性(属性的值 是另外 一个类的对象)的方式,可以间接地将两个类关联、整合、组合到一起,从而减少类与类之间代码的冗余。

  1. class Foo:
  2. xxx=111
  3. class bar:
  4. yyy=222
  5. def zzz(self):
  6. print('bar的方法')
  7. obj=Foo()
  8. obj1=bar()
  9. #obj.attr='大海’ --->添加新值,创建属性
  10. #print(obj.attr)
  11. obj.attr=obj1 #---->添加对象,进行组合
  12. # 组合在一起,obj.attr 等价于obj1
  13. print(obj.xxx)
  14. print(obj.attr.yyy)
  15. obj.attr.zzz()
  1. class People:
  2. school = '图灵学院'
  3. def __init__(self,name,age,sex):
  4. self.name = name
  5. self.age = age
  6. self.sex = sex
  7. class Student(People):
  8. def __init__(self, name, age, sex,score=0):
  9. super().__init__(name, age, sex)
  10. self.score = score
  11. class Teacher(People):
  12. def __init__(self,name,age,sex,course=[]):
  13. super().__init__(name, age, sex)
  14. self.course=course
  15. def tell_info1(self):
  16. # 这个时候是列表里面装了4个课程对象
  17. # print(self.course)
  18. for i in self.course:
  19. # print(i)
  20. # 课程属性
  21. # print('<课程名:%s,价格%s>' % (i.c_name, i.c_price))
  22. # 课程方法
  23. i.tell_info()
  24. class Course:
  25. def __init__(self,c_name,c_price):
  26. self.c_name = c_name
  27. self.c_price = c_price
  28. def tell_info(self):
  29. print('<课程名:%s,价格%s>'%(self.c_name,self.c_price))
  30. python = Course('python开发',10000)
  31. math = Course('高等数学',3000)
  32. English = Course('英语',4000)
  33. music = Course('音乐',5000)
  34. drawing = Course('绘画',6000)
  35. dahai = Teacher('大海',24,'man')
  36. # print(dahai)
  37. # 把music课程对象添加到老师对象tea的属性里面
  38. # dahai.course = music
  39. # print(dahai.course)
  40. # print(music)
  41. # dahai.course.tell_info()
  42. # dahai.course = math
  43. # dahai.course.tell_info()
  44. # 如果我想把一堆的对象放到一个对象属性里面,我们怎么做?
  45. # 思考一下? 放到一个容器里面 列表
  46. # print(dahai.course)
  47. # dahai.course = music
  48. # print(dahai.course)
  49. dahai.course.append(python)
  50. dahai.course.append(math)
  51. dahai.course.extend([English,music])
  52. # 这个时候是列表里面装了4个课程对象
  53. print(dahai.course)
  54. print('===================')
  55. dahai.tell_info1()

组合和继承的区别:

继承是把全部的属性和方法让子类可以调用,而组合只是部分的属性和方法把2个类关联到一起,

有些类的属性不能全部继承,这就用到了组合,组合的是对象,而继承 的是,类

继承 是在类定义产生的,它是类之间的关联关系,

而组合是类定义后产生的关系,因为它是对象的关联关系

8.多态

8.1.什么是多态

多态指的是同一种/类事物的不同形态,比如动物有多种形态:猫,狗,猪。

8.2.为何要用多态

多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象

多态性的精髓:统一

8.3.如何用多态

1.定义一个多态性的方法

  1. class Animal:
  2. # 动物都会叫
  3. def speak(self):
  4. print('我是动物我会说话')
  5. class People(Animal):
  6. def speak(self):
  7. print('say hello')
  8. class Dog(Animal):
  9. def speak(self):
  10. print('汪汪汪')
  11. class Pig(Animal):
  12. def speak(self):
  13. print('哼哼哼')
  14. # 三个对象都是动物
  15. obj1=People()
  16. obj2=Dog()
  17. obj3=Pig()

2.多态性的精髓:统一

多态性的好处在于增强了程序的灵活性和可扩展性,比如通过继承Animal类创建了一个新的类型,实例化得到的对象obj,可以使用相同的方式使用object.speak()

  1. # 多态性的精髓:统一
  2. # 学车,学的是小汽车标准,会了所有的小汽车都会开
  3. obj1.speak()
  4. obj2.speak()
  5. obj3.speak()
  6. # 内置方法多态方法
  7. # len()
  8. # 计算多个值的长度

3.python中一切皆对象,数据类型本身就是对象,本身就支持多态性

  1. print(len([1, 2, 3, 4]))
  2. print(len('1234'))
  3. print(len((1, 2, 3, 4)))
  4. # 计算多个值的长度,如果按照以下这样就缺乏了多态性,灵活性就弱
  5. # size()
  6. # zhangdu()
  7. # kuangdu()

9.常用的魔法方法

9.1. str

在对象被打印时自动触发,可以用来定义对象被打印时的输出信息

  1. class People:
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.age = age
  5. def __str__(self):
  6. return '<name:%s age%s>'%(self.name,self.age)
  7. def run(self):
  8. return self.name
  9. obj = People('大海',18)
  10. print(obj)
  11. print(obj.run())

9.2. del

在对象被删除时先自动触发该方法,可以用来回收对象以外其他相关资源,比如系统资源

  1. # # __del__
  2. # import time
  3. class Foo:
  4. def __init__(self,x,filepath,encoding='utf8'):
  5. self.x=x
  6. self.f=open(filepath,'rt',encoding=encoding)
  7. def __del__(self):
  8. print('__del__正在运行')
  9. self.f.close()
  10. obj = Foo(1,'a.txt')
  11. # # print(obj.f.read())
  12. # # obj.f.close()
  13. # print('不是对象生成运行__del__,对象正在使用的时候不会运行')
  14. # time.sleep(3)
  15. # 对象使用不会运行__del__
  16. # print(obj.f.read())

9.3. call

在对象被调用时会自动触发该方法

  1. # __call__: 在对象被调用时会自动触发该方法
  2. class Foo:
  3. def __init__(self,name,age):
  4. self.name = name
  5. self.age = age
  6. def __call__(self, *args, **kwargs):
  7. print(self,args,kwargs)
  8. def run(self):
  9. print('run')
  10. obj1 = Foo(1,2)
  11. obj1.run()
  12. # 没写__call__不可以调用
  13. # obj1()
  14. # 写了__call__可以调用
  15. # obj1()
  16. # obj1(1,2,x=3,y=4)
  17. # # 省略了
  18. # obj1.__call__(1,2,x=3,y=4)