面向对象-组合
1.什么是组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
1 class Foo: 2 xxx = 111 3 4 class Bar: 5 yyy = 222 6 7 obj = Foo() 8 obj.attr = Bar() 9 10 print(obj.xxx) 11 >>>111 12 print(obj.attr.yyy) 13 >>>222
2.为何要用组合
通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起
从而减少类与类之间代码冗余
1 class Foo1: 2 pass 3 class Foo2: 4 pass 5 class Foo3: 6 pass 7 8 class Bar: 9 pass 10 11 obj_from_bar=Bar() 12 13 obj1=Foo1() 14 obj2=Foo2() 15 obj3=Foo3() 16 17 obj1.attr1=obj_from_bar 18 obj2.attr2=obj_from_bar 19 obj3.attr3=obj_from_bar
3.如何用组合
1 class OldboyPeople: 2 school = 'Oldboy' 3 4 def __init__(self, name, age, sex, ): 5 self.name = name 6 self.age = age 7 self.sex = sex 8 9 10 class OldboyStudent(OldboyPeople): 11 def __init__(self, name, age, sex, score=0): 12 OldboyPeople.__init__(self, name, age, sex) 13 self.score = score 14 self.courses = [] 15 16 def choose_course(self): 17 print('%s choosing course' % self.name) 18 19 def tell_all_course(self): 20 print(('学生[%s]选修的课程如下' % self.name).center(50, '=')) 21 for obj in self.courses: 22 obj.tell_info() 23 print('=' * 60) 24 25 26 class OldboyTeacher(OldboyPeople): 27 def __init__(self, name, age, sex, level): 28 OldboyPeople.__init__(self, name, age, sex) 29 self.level = level 30 self.courses = [] 31 32 def score(self, stu, num): 33 stu.score = num 34 35 def tell_all_course(self): 36 print(('老师[%s]教授的课程如下' % self.name).center(50, '*')) 37 for obj in self.courses: 38 obj.tell_info() 39 print('*' * 70) 40 41 42 class Course: 43 def __init__(self, c_name, c_price, c_period): 44 self.c_name = c_name 45 self.c_price = c_price 46 self.c_period = c_period 47 48 def tell_info(self): 49 print('<课程名:%s 价钱:%s 周期:%s>' % (self.c_name, self.c_price, self.c_period)) 50 51 52 # 创建课程对象 53 python = Course('python全栈开发', 1900, '5mons') 54 linux = Course('linux架构师', 900, '3mons') 55 56 stu1 = OldboyStudent('刘二蛋', 38, 'male') 57 stu1.courses.append(python) 58 stu1.courses.append(linux) 59 stu1.tell_all_course() 60 61 tea1 = OldboyTeacher('egon', 18, 'male', 10) 62 tea1.courses.append(python) 63 tea1.tell_all_course()
面向对象-多态与多态性
1.什么是多态
多态指的是同一种/类事物的不同形态
2.为何要用多态
多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
3.如何用多态
Animal() #父类只是用来建立规范的,不能用来实例化,更无需实现内部的方法
1 import abc 2 3 4 class Animal(metaclass=abc.ABCMeta): 5 @abc.abstractmethod 6 def speak(self): 7 pass 8 9 @abc.abstractmethod 10 def run(self): 11 pass 12 13 14 15 class People(Animal): 16 def speak(self): 17 print('say hello') 18 19 def run(self): 20 pass 21 22 23 class Dog(Animal): 24 def speak(self): 25 print('汪汪汪') 26 27 def run(self): 28 pass 29 30 31 class Pig(Animal): 32 def speak(self): 33 print('哼哼哼') 34 35 def run(self): 36 pass 37 38 39 obj1 = People() 40 obj2 = Dog() 41 obj3 = Pig()
Python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
1 class Disk: 2 def read(self): 3 print('Disk read') 4 5 def write(self): 6 print('Disk write') 7 8 9 class Memory: 10 def read(self): 11 print('Mem read') 12 13 def write(self): 14 print('Mem write') 15 16 17 class Cpu: 18 def read(self): 19 print('Cpu read') 20 21 def write(self): 22 print('Cpu write') 23 24 25 obj1 = Disk() 26 obj2 = Memory() 27 obj3 = Cpu() 28 29 obj1.read() 30 obj2.read() 31 obj3.read()
面向对象-封装
1.什么是封装
装: 往容器/名称空间里存入名字
封: 代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内
2.为何要封装
封装数据属性:
将数据属性隐藏起来,类外就无法直接操作属性,需要类内部开辟一个接口,让外部的使用可以间接地操作属性,可以在接口内定制任意的控制逻辑,从而严格控制使用者对属性的操作
1 class People: 2 def __init__(self, name, age): 3 self.__name = name 4 self.__age = age 5 6 def tell_info(self): 7 print('<name:%s age:%s>' % (self.__name, self.__age)) 8 9 def set_info(self, name, age): 10 if type(name) is not str: 11 print('名字必须是str类型傻叉') 12 return 13 if type(age) is not int: 14 print('年龄必须是int类型傻叉') 15 return 16 self.__name = name 17 self.__age = age 18 19 20 obj = People('egon', 18) 21 obj.set_info('EGON', '18') 22 obj.tell_info()
封装函数属性: 隔离复杂度
1 class ATM: 2 def __card(self): 3 print('插卡') 4 5 def __auth(self): 6 print('用户认证') 7 8 def __input(self): 9 print('输入取款金额') 10 11 def __print_bill(self): 12 print('打印账单') 13 14 def __take_money(self): 15 print('取款') 16 17 def withdraw(self): 18 self.__card() 19 self.__auth() 20 self.__input() 21 self.__print_bill() 22 self.__take_money() 23 24 25 a = ATM() 26 a.withdraw()
3.如何封装
在类内定义的属性前加__开头(没有__结尾)
总结:
1. __开头的属性实现的隐藏仅仅只是一种语法意义上的变形,并不会真的限制类外部的访问
2. 该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性并不会变形
3. 如果父类不想让子类覆盖自己的属性,可以在属性前加__开头
1 class Foo: 2 def __f1(self): # _Foo__f1 3 print('Foo.f1') 4 5 def f2(self): 6 print('Foo.f2') 7 self.__f1() # obj._Foo__f1() 8 9 10 class Bar(Foo): 11 def __f1(self): # _Bar__f1 12 print('Bar.f1') 13 14 15 obj = Bar() 16 17 >>>Foo.f2 18 >>>Foo.f1
面向对象-property
property装饰器是用来将类内的函数属性伪装成数据属性
1 class People: 2 def __init__(self, name): 3 self.__name = name 4 5 @property 6 def name(self): 7 return '<名字:%s>' % self.__name 8 9 @name.setter 10 def name(self, obj): 11 if type(obj) is not str: 12 print('name必须为str类型') 13 return 14 self.__name = obj 15 16 @name.deleter 17 def name(self): 18 print('不让删') 19 20 obj = People('egon') 21 del obj.name 22 print(obj.__dict__)