python之路--day21--组合与封装
讲在组合之前:
解决类和类之间代码冗余问题有两种解决方案:1,继承 2,组合
1,继承:描述的是类和类之间,什么是什么的关系,一种从属关系
2,组合:描述的是类和类之间的关系。是一种什么有什么的关系
组合:一个类产生的对象,该对象拥有一个属性,这个属性的值来自于另外一个类的对象
class OldboyPeople: school = 'oldboy' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) self.level=level self.salary = salary def change_score(self): print('......................') class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,course): super().__init__(name,age,sex) self.course = course def change_score(self): print('......................') tea1 = OldboyTeacher('egon',18,'male',9,3.1) data_obj = Data(2000,1,1) tea1.birth = data_obj ## ## 此处:为tea1对象新增了一个属性birth,这个属性的值是Data实例化的对象data_obj....这就是类的组合 ## ##
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex,): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) self.level=level self.salary=salary self.courses=[] def change_score(self): print('teacher %s is changing score' %self.name) def tell_course_info(self): print(('老师%s 教授的课程信息如下' %self.name).center(50,'=')) for course_obj in self.courses: course_obj.info() class Oldboystudent(OldboyPeople): def __init__(self,name,age,sex): super().__init__(name,age,sex,) self.courses=[] def choose(self): print('student %s choose course' %self.name) def tell_course_info(self): print(('学生%s 学习的课程信息如下' % self.name).center(50, '=')) for course_obj in self.courses: course_obj.info() class Course: def __init__(self,cname,period,price): self.cname=cname self.period=period self.price=price def info(self): print('课程信息<名字:%s 周期:%s 价钱:%s>' %(self.cname,self.period,self.price)) tea1=OldboyTeacher('egon',18,'male',9,3.1) stu1=Oldboystudent('张三',16,'male') python=Course('Python全栈开发','5mons',3000) linux=Course('Linux高级架构师','5mons',2000) go=Course('Go开发工程师','3mons',1000) # # 给老师添加课程 # tea1.courses.append(python) # tea1.courses.append(linux) # print(tea1.courses) # tea1.courses[0].info() # for course_obj in tea1.courses: # course_obj.info() # tea1.tell_course_info() # 给学生添加课程 stu1.courses.append(python) stu1.courses.append(go) stu1.courses.append(linux) stu1.tell_course_info()
封装:
什么是封装:
装就是把一堆属性存起来,封就是把这些属性给隐藏起来
强调:封装单从字面意思看就等同于隐藏,但其实封装绝对不是单纯意义的隐藏
为什么要用封装:
最终目的:明确区分内外,对内部开发,对外部隐藏
封装数据属性的目的:把数据属性封装起来,然后需要开辟接口给类外部的使用者使用。然后在接口上添加控制逻辑,
从而严格控制访问者对属性的操作
class People: def __init__(self,name,age): self.__name=name self.__age=age def tell_info(self): print(self.__name,self.__age) def set_info(self,name,age): if type(name) is not str: raise TypeError('用户名必须为str类型') if type(age) is not int: raise TypeError('年龄必须为int类型') self.__name=name self.__age=age
封装函数属性的目的:隔离复杂度
class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() obj=ATM() obj.withdraw()
如何用封装
在属性前面就是 __开头(一定注意不要加__结尾)
特征:1,__开头隐藏属性,只是语法上的一种变形,对外不对内
什么是对外不对内:为一个属性加__开头,会在类定义阶段将属性名统一变形为:_ 自己的类名__ 属性名
class Foo: __x=1111 #_Foo__x=1111 def __init__(self,y): self.__y=y #self._Foo__y=y def __f1(self): #_Foo__f1 print('Foo.f1') def get_y(self): print(self.__y) # print(self._Foo__y) #类内部在定义阶段全部做了语法上的修改,所以内部可以访问__开头的属性 #但是类外部无法直接通过属性名访问类内部属性
2,这种语法上的变形,只在类定义阶段生效一次,定义阶段之后再定义的__开头的属性,没有隐藏的效果
# Foo.__aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1 # print(Foo.__dict__) # obj.__bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=2 # print(obj.__dict__)
3,如果父类不想子类覆盖掉自己的属性,可以在定义阶段在使用__开头,隐藏属性、
class Foo: def __f1(self): #_Foo__f1 print('Foo.f1') def f2(self): print('Foo.f2') self.__f1() #obj._Foo__f1() class Bar(Foo): def __f1(self): #_Bar__f1 print("Bar.f1") obj=Bar() obj.f2()