python 之 面向对象基础(组合和封装)

7.4 组合

解决类与类之间代码冗余问题有两种解决方案:

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)
​
​
tea1=OldboyTeacher('egon',18,'male',9,3.1)  #创建老师类的对象tea1
date_obj=Date(2000,1,1)                    #创建Date类的对象date_obj
date_obj.tell_birth()                      #date_obj可以调用绑定方法tell_birth
​
tea1.birth=date_obj                        #tea1的birth属性来自于Date类的一个对象date_obj   
tea1.birth.tell_birth()                     #tea1的birth属性可以调用tell_birth属性                    
stu1=Oldboystudent('张三',16,'male','linux')
stu1.birth=Date(2002,3,3)
stu1.birth.tell_birth()
stu1.choose()                               #使用stu1将两个类联系起来
View Code

7.5 封装

什么是封装: 装就是把一堆属性存起来,封的概念就把这些属性给隐藏起来,其实这种隐藏只是一种语法上的变形,对外不对内

注意:

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

class Foo:
    x=1
    __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)               # 1          
print(obj.__x)              # 报错
print(obj._Foo__x)         # 1111
​
obj.__f1()                 #报错
obj._Foo__f1()             # Foo.f1
print(obj.y)               #报错
print(obj.__y)             #报错
print(obj._Foo__y)         # 22222
obj.get_y()                # 22222 明确地区分内外,对外是隐藏的,对内是开放的

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

Foo.__aaa=1
print(obj.__aaa) # 1

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

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()    # Foo.f2 Foo.f1

7.51 封装的作用

封装数据属性的目的:

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

class People:
    def __init__(self,name):
            self.__name=name
​
     def tell_name(self):
                # 添加逻辑
                return self.__name
            
 obj=People('egon')
 #obj.__name
 obj.tell_name()

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

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

7.52 封装之property

用来将类内的函数伪装成一个数据属性

例:

体质指数()体重()身高()

  首先需要明确 : bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能 都会立即计算一个值

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
​
    @property           #于是我们需要为bmi这个函数添加装饰器,将其伪装成一个数据属性
    def bmi(self):
        return self.weight / (self.height * self.height)
    
egon=People('egon',75,1.80)
yl=People('yangli',85,1.74)
# print(egon.bmi())
# print(yl.bmi())
print(egon.bmi)         # 21.604938271604937,调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值
print(yl.bmi)           # 把功能伪装成一个属性

@name.setter 和 @name.deleter

# egon.bmi=123 
# egon.bmi背后对应的是一个函数,所以不能赋值
class People:
    def __init__(self,name):
        self.__name=name
​
    @property
    def name(self): 
         # 添加逻辑
        return self.__name
​
    @name.setter
    def name(self,x):
         # 添加逻辑
        self.__name=x
​
    @name.deleter
    def name(self):
         # 添加逻辑
        del self.__name
​
obj=People('egon')
print(obj.name)  # egon
                       # 修改
obj.name='EGON'         # 现在可以赋值
print(obj.name)         # EGON
del obj.name            # 删除
​
obj.name                # 报错
posted @ 2019-07-04 22:03  small_white-  阅读(396)  评论(0编辑  收藏  举报