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()
不让子类覆盖父类的同名属性

 

posted @ 2018-04-13 21:03  木夂口  阅读(172)  评论(0编辑  收藏  举报
levels of contents