组合、多态、封装、property装饰器
一、组合
1、什么是组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
1 class Foo(): 2 pass 3 4 class Bar(): 5 pass 6 7 obj=Bar() 8 obj.attrib=Foo()
2、组合的作用
通过为某一个对象添加属性(属性值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起,从而减少类与类之间代码冗余
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 12 def __init__(self, name, age, sex, score=0): 13 super().__init__(name, age, sex) 14 self.score = score 15 self.courses = [] 16 17 def choose_course(self): 18 print('%s choosing course' % self.name) 19 20 def tell_all_course(self): 21 print(('学生[%s]的课程如下' % self.name).center(60, '=')) 22 for course in self.courses: 23 course.tell_course() 24 print('=' * 80) 25 26 27 class OldboyTeacher(OldboyPeople): 28 29 def __init__(self, name, age, sex, level): 30 super().__init__(name, age, sex) 31 self.level = level 32 self.courses = [] 33 34 def score(self, stu, num): 35 stu.score = num 36 37 def tell_all_course(self): 38 print(('老师[%s]教授的课程如下' % self.name).center(70, '-')) 39 for course in self.courses: 40 course.tell_course() 41 print('-' * 80) 42 43 44 class Course: 45 def __init__(self, c_name, c_price, c_period): 46 self.c_name = c_name 47 self.c_price = c_price 48 self.c_period = c_period 49 50 def tell_course(self): 51 print('<课程名:%s 价格:%s 时间:%s>' % (self.c_name, self.c_price, self.c_period)) 52 53 54 python = Course('python全栈开发', 10000, 5) 55 linux = Course('linux架构', 12000, 5) 56 57 stu = OldboyStudent('zs', 18, 'male') 58 stu.courses.append(python) 59 stu.courses.append(linux) 60 stu.tell_all_course() 61 62 teach = OldboyTeacher('egon', 18, 'male', 10) 63 teach.courses.append(python) 64 teach.tell_all_course()
二、多态与多态性
1、什么是多态
多态指的是同一种/类事物的不同形态
1 class Animal: 2 def speak(self): 3 pass 4 5 class People(Animal): 6 def speak(self): 7 print('say hello') 8 9 class Dog(Animal): 10 def speak(self): 11 print('汪汪汪') 12 13 class Pig(Animal): 14 def speak(self): 15 print('哼哼哼')
2、抽象类
只是用来建立规范的,不能用来实例化的,更无需实现内部的方法
1 import abc 2 3 class Animal(metaclass=abc.ABCMeta): 4 @abc.abstractmethod 5 def speak(self): 6 pass 7 8 @abc.abstractmethod 9 def run(self): 10 pass 11 12 class People(Animal): 13 def speak(self): 14 print('say hello') 15 16 def run(self): 17 pass 18 19 class Dog(Animal): 20 def speak(self): 21 print('汪汪汪') 22 23 def run(self): 24 pass 25 26 class Pig(Animal): 27 def speak(self): 28 print('哼哼哼') 29 30 def run(self): 31 pass 32 33 obj1=People() 34 obj2=Dog() 35 obj3=Pig()
三、封装
1、什么是封装
装:往容器/名称空间里存入名字
封:代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内
2、怎么封装
(1)在类内定义的属性前加__开头(没有__结果)
(2)__开头的属性实现的隐藏仅仅只是一种语法意义上的变形,并不会真的限制类外部的访问,外部可以调用类内的接口来操作属性
(3)该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性并不会变形
1 class Foo: 2 __x=111 # _Foo__x 在定义的时候已经将__x改为_Foo__x 3 __y=222 # _Foo__y 在定义的时候就将__y改成_Foo__y 4 5 def __init__(self,name,age): 6 self.__name=name # 函数再定义的时候添加属性,可以被封装 7 self.__age=age 8 9 def __func(self): # 在定义的时候已经将__func改为_Foo__func 10 print('func') 11 12 def get_info(self): 13 print(self.__name,self.__age,self.__x) # 内部可以访问封装的属性 14 15 print(self._Foo__name,self._Foo__age,self._Foo__x) 16 17 print(Foo.__x) # 报错 无法直接访问封装的属性 18 19 print(Foo.__dict__) 20 21 print(Foo._Foo__x) # 111 封装只是在属性前面加了“_类名”,可以访问封装的属性 22 23 Foo.__z=333 24 25 print(Foo.__z) # 333 后期添加的属性不会被封装,封装只发生在类定义的阶段
3、封装数据属性
(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.tell_info() 22 23 # obj.set_info('EGON',19) 24 # obj.set_info(123,19) 25 obj.set_info('EGON','18') 26 obj.tell_info()
4、封装函数属性
1 class ATM: 2 def __card(self): 3 print('插卡') 4 def __auth(self): 5 print('用户认证') 6 def __input(self): 7 print('输入取款金额') 8 def __print_bill(self): 9 print('打印账单') 10 def __take_money(self): 11 print('取款') 12 13 def withdraw(self): 14 self.__card() 15 self.__auth() 16 self.__input() 17 self.__print_bill() 18 self.__take_money() 19 20 a=ATM() 21 a.withdraw()
四、property装饰器
property装饰器是用来将类内的函数属性伪装成数据属性
1 class People: 2 def __init__(self, weight, height): 3 self.weight = weight 4 self.height = height 5 6 @property # property装饰器 7 def bmi(self): 8 return self.weight / (self.height ** 2) 9 10 11 obj = People(70, 1.75) 12 13 print(obj.bmi) # bmi被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 del self.__name 20 21 obj=People('egon') 22 23 print(obj.name) # egon 24 obj.name='EGON' 25 #obj.name=123 26 print(obj.name) # EGON