python 之 面向對象基礎(組合和封裝)

7.4 組合

解決類與類之間代碼冗餘問題有兩種解決方案:

1、繼承:描述的是類與類之間,什麼是什麼的關係

2、組合:描述的是類與類之間的關係,是一種什麼有什麼的關係

一個類產生的對象,該對象擁有一個屬性,這個屬性的值是來自於另外一個類的對象

《python 之 面向對象基礎(組合和封裝)》
《python 之 面向對象基礎(組合和封裝)》

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                # 報錯
点赞

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *