目录
上节课内容回顾
#1 如何使用继承 #基类,父类 class Person: school='oldboy' def __init__(self,name,age): self.name=name self.age=age #子类,派生类 class Student(Person): pass stu=Student('nick',18) #2 通过继承减少代码冗余 class Person: school='oldboy' def __init__(self,name,age): self.name=name self.age=age #子类,派生类 class Student(Person): def __init__(self,name,age,course): #如何重用父类的方法 Person.__init__(self,name,age) #严重错误的Person() 是实例化,产生对象,对象调用自己的绑定方法__init__ Person().__init__() ss=Person() # ss.__init__(name,age,course) self.course=course #属性查找顺序 #原来:对象--->类--->报错 #学了继承:对象--->类--->父类--->父类......---->报错 #父类的查找顺序 #多层继承查找顺序:一条线往上找到底 #多继承(横向):从左往右的顺序 #横向的多层继承 # -不形成菱形:从左侧开始一直往上找到底,再从左侧第二个开始往上找到底... #-形成菱形: # -新式类:继承了object的类(以及它的子类)都叫新式类,py3中都是新式类,因为默认都继承了object,py2中需要手动的继承object # -经典类:py2中没有继承object的就是经典类 # -新式类:广度优先,菱形的顶点最后才找 # -经典类:深度优先,菱形顶点在第一次分支就找到 #如何重用父类的方法二 #通过super关键字 class Person(object): school = 'oldboy' def __init__(self,name,age): self.name=name self.age=age def study(self): print('study....') class Student(Person): school = 'yyyy' def __init__(self,name,age,course): #相当于生成了一个特殊对象,对象调用绑定方法,不需要传第一个参数 #严格按照继承的查找顺序(mro列表找得) super().__init__(name,age) self.course=course def study(self): # Person.study(self) super().study() # print("%s学生在学习"%self.name) #派生
今日学习内容
一、组合
1.1 什么是组合
对象的某个属性是另一个类的对象
组合的概念:
class Foo: def __init__(self,bar): self.bar=bar class Bar: pass # f=Foo() bar=Bar() # f=Foo(Bar()) f=Foo(bar)
1.2 为什么使用组合
可以减少代码冗余
不使用组合方法:
class Person: school = 'oldboy' class Teacher(Person): def __init__(self,name,age,level,course_name,course_price,course_period): self.name=name self.age=age self.level=level class Student(Person): def __init__(self,name,age,course,course_name,course_price,course_period): self.name=name self.age=age self.course=course
使用组合方法:
class Person: school = 'oldboy' class Teacher(Person): def __init__(self,name,age,level,course): self.name=name self.age=age self.level=level #course是课程对象,表示老师教授的课程 self.course=course class Student(Person): def __init__(self,name,age,course): self.name=name self.age=age # course是课程对象,表示学生选的课程 self.course = course class Course: def __init__(self,course_name,course_price,course_period): self.name=course_name self.price=course_price self.period=course_period course=Course('Python',20180,7) stu=Student('nick',19,course) teacher=Teacher('nick',19,'高级',course) #查看老师教授的课程名 print(teacher.course.name)
1.3 如何使用组合
class Person: school = 'oldboy' class Teacher(Person): def __init__(self,name,age,level,course): self.name=name self.age=age self.level=level #course是课程对象,表示老师教授的课程 self.course=course class Student(Person): # course=[] #错误 def __init__(self,name,age): self.name=name self.age=age # course是课程对象,表示学生选的课程 self.course_list = [] def choose_course(self,course): # self.course=[] #错误 #把课程对象追加到学生选课的列表中 self.course_list.append(course) def tell_all_course(self): #循环学生选课列表,每次拿出一个课程对象 for course in self.course_list: #课程对象.name 取到课程名字 print(course.name) class Course: def __init__(self,course_name,course_price,course_period): self.name=course_name self.price=course_price self.period=course_period course=Course('Python',20199,7) stu1=Student('nick',19) stu1.choose_course(course) stu2=Student('王二丫',19) stu2.choose_course(course) stu2.choose_course(Course('linux',19999,5)) #查看stu1选的所有课程名称 #方式一(通过普通函数) # def tell_all_course(student): # for course in student.course_list: # print(course.name) # # # tell_all_course(stu1) # tell_all_course(stu2) #方式二(通过对象的绑定方法) # stu1.tell_all_course() stu2.tell_all_course()
1.4 扩展部分
组合和继承
什么时候用组合,什么时候用继承
- 什么是什么的关系用继承
- 什么有什么的关系用组合
二、多态和多态性
2.1 什么是多态?
一类事物的多种形态
比如:动物类:人、猫、狗
2.2 多态性
多态性是指在不考虑实例类型的情况下使用实例
2.3 使用多态的好处
1.增加了程序的灵活性
2.增加了程序的可扩展性
示例:
#多态基础 class Animal: def speak(self): pass class Pig(Animal): def speak(self): print('哼哼哼') class Dog(Animal): def speak(self): print('汪汪') class People(Animal): def speak(self): print('say hello') pig=Pig() dog=Dog() people=People() pig.speak() dog.speak() people.speak() def animal_speak(obj): obj.speak() animal_speak(pig) animal_speak(people) def len(obj): return obj.__len__() len('xxxx') len([1,2,3])
2.4 两种约束代码的方式
第一种方式:用abc实现接口统一化,约束代码(用的比较少)
import abc # 第一在括号中写metaclass=abc.ABCMeta class Animal(metaclass=abc.ABCMeta): # 第二在要约束的方法上,写abc.abstractmethod装饰器 @abc.abstractmethod def speak(self): pass class Pig(Animal): def speak(self): print('哼哼哼') class Dog(Animal): def yy(self): print('汪汪') class People(Animal): def zz(self): print('say hello') people = People() people.zz() # 这样就不能利用多态性 def animal_speak(obj): obj.speak() pig = Pig()
第二种方式:用异常处理来实现(常用)
class Animal(): def speak(self): #主动抛出异常 raise Exception('你得给我重写它啊') class Pig(Animal): def speak(self): print('哼哼哼') class People(Animal): def speak(self): print('say hello') pig=Pig() pe=People() def animal_speak(obj): obj.speak() animal_speak(pig) animal_speak(pe)
2.5 鸭子类型
鸭子类型:只要走路像鸭子(对象中有某个绑定方法),那你就是鸭子
# 鸭子类型的写法 # 内存类 class Memory: def read(self): print('Memory...read') def write(self): print('Memory...write') class Network: def read(self): print('Network...read') def write(self): print('Network...write') def read(obj): obj.read() m = Memory() n = Network() read(m) read(n)
三、封装
3.1 封装是什么意思?
从封装本身的意思去理解:
封装就好像是拿一个麻袋,把小猫,小狗等,一起装进麻袋,然后把麻袋封上口子
3.2 如何隐藏
把东西包装进去之后,隐藏起来,外部访问不到
3.3 如何用代码实现隐藏
隐藏属性/隐藏方法,隐藏之后,外部访问不到,只有内部能够访问
隐藏属性:通过__变量名来隐藏
隐藏方法:通过__方法名来隐藏
隐藏属性主要是为了安全
#name 隐藏起来 # class Person: # def __init__(self,name,age): # self.__name=name # self.__age=age # def get_name(self): # # print(self.__name) # return '[----%s-----]'%self.__name # # p=Person('nick',89) # print(p.age) #访问name # print(p.name) # print(p.__name) # print(p.get_name()) #隐藏的属性访问不到?实际上有方法能访问到 #通过变形隐藏了属性 # print(p._Person__name) # print(p.__dict__) #隐藏方法:隔离复杂度 # class Person: # def __init__(self,name,age): # self.__name=name # self.__age=age # def __speak(self): # print('6666') # # p=Person('nick',89) # p.__speak() # print(Person.__dict__) # p._Person__speak() #什么时候属性变形,只要再类内部,以__变量名 命名的变量,都会被隐藏,会发生的变形,在外部放入的 __变量名 属性是不隐藏的 # class Person: # def __init__(self,name,age): # self.__name=name # self.__age=age # def set_xx(self,xx): # self.__xx=xx # # p=Person('nick',18) # # ._p_xx="xxx" # # p.set_xx('6688') # print(p.__dict__)
今日总结
暂无