Python之旅.第五章.面向对象

一、组合

解决类与类之间代码冗余问题有两种解决方案:1、继承 2、组合

1、继承:描述的是类与类之间,什么是什么的关系

2、组合:描述的是类与类之间的关系,是一种什么有什么关系;一个类产生的对象,该对象拥有一个属性,这个属性的值是来自于另外一个类的对象

#组合不属于继承

#类的使用将变量及处理其的函数捆绑起来

#继承是强耦合,组合是解耦合

 

class Date:

    def __init__(self,year,mon,day):

        self.year = year

        self.mon = mon

        self.day = day

    def tell_birth(self):

        print('出生年月日<%s-%s-%s>' % (self.year, self.mon, self.day))

 

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('teacher %s is changing score' %self.name)

 

class Oldboystudent(OldboyPeople):

    def __init__(self,name,age,sex,course,):

        super().__init__(name,age,sex,)

        self.course=course

    def choose(self):

        print('student %s choose course' %self.name)

 

stu1=Oldboystudent('张三',16,'male','linux')

stu1.birth=Date(2002,3,3)

stu1.birth.tell_birth()

 

二、组合练习

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()

 

三、如何封装以及封装的目的

1、什么是封装:

装就是把一堆属性存起来,封的概念就把这些属性给隐藏起来

强调:封装单从字面意思去看等同于隐藏,但其实封装绝对不是单纯意义的隐藏

 

2、如何用封装

如何把属性隐藏起来,就在属性前面加上__开头(注意不要加__结尾)

注意:

a、其实这种隐藏只是一种语法上的变形,对外不对内

为一个属性名加__开头(注意不要加__结尾),会在类定义阶段将属性名统一变形:_自己的类名__属性名

 

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)

 

obj=Foo(22222)

print(obj.x)

print(obj.__x)

obj.__f1()

print(obj.y)

print(obj.__y)

print(Foo.__dict__)

print(obj._Foo__x)

print(obj._Foo__y)

obj._Foo__f1()

obj.get_y()

 

b、这种语法意义上变形,只在类定义阶段发生一次,类定义之后,新增的__开头的属性都没有变形的效果

 

Foo.__aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1

print(Foo.__dict__)

 

obj.__bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=2

print(obj.__dict__)

 

c、如果父类不想让子类覆盖自己的方法,可以在方法名前加__开头

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()

 

3、为什么要用封装

a、封装数据属性的目的:把数据属性封装起来,然后需要开辟接口给类外部的使用者使用,好处是我们可以在接口之上添加控制逻辑,从而严格空间访问者对属性的操作

class People:

    def __init__(self,name,age):

        self.__name=name

        self.__age=age

    def tell_info(self):

        u=input('user>>: ').strip()

        p=input('pwd>>: ').strip()

        if u == 'egon' and p == '123':

            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

 

p=People('egon',18)

p.tell_info()

p.tell_info()

p.set_info('EGON',19)

p.tell_info()

p.set_info(353535353535353535,20)

p.set_info('EGON','20')

 

b、封装函数属性的目的:为了隔离复杂度

 

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()s

 

c、封装的终极奥义:明确地区分内外,对外是隐藏的,对内是开放的

posted @ 2018-04-15 20:07  yangli0504  阅读(129)  评论(0编辑  收藏  举报