1. 程式人生 > >學習python課程第二十三天

學習python課程第二十三天

編寫程序 fun inpu level @property ini 代碼冗余 單純 student

一. 組合 :

  1. 什麽是組合 ?

    一個對象的屬性是來自於另外一個類的對象, 稱之為組合. (跟繼承其實很相似.都是共用一個類裏面的屬性)

  2. 為何用組合 ?

    組合也是用來解決類與類代碼冗余的問題.

  3. 如何用組合 ?

  

class Foo:
aaa=1111
def __init__(self,x,y):
self.x=x
self.y=y

def func1(self):
print(‘Foo內的功能‘)


class Bar:
bbb=2222
def __init__(self, m, n):
self.m = m
self.n = n

def func2(self):
print(‘Bar內的功能‘)

obj1=Foo(10,20)
obj2=Bar(30,40)

obj1.xxx=obj2 (把兩個類組合到了一起.)


print(obj1.x,obj1.y,obj1.aaa,obj1.func1)
print(obj1.xxx.m,obj1.xxx.n,obj1.xxx.bbb,obj1.xxx.func2)


  

  小練習 :

class OldboyPeople:
school = ‘Oldboy‘
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

class OldboyStudent(OldboyPeople):
def choose_course(self):
print(‘%s is choosing course‘ %self.name)

class OldboyTeacher(OldboyPeople):
def __init__(self, name, age, gender,level,salary):
OldboyPeople.__init__(self, name, age, gender)
self.level=level
self.salary=salary

def score(self,stu,num):
stu.num=num
print(‘老師%s給學生%s打分%s‘ %(self.name,stu.name,num))

class Course:
def __init__(self,course_name,course_price,course_period):
self.course_name=course_name
self.course_price=course_price
self.course_period=course_period

def tell_course(self):
print(‘課程名:<%s> 價錢:[%s] 周期:[%s]‘ % (self.course_name, self.course_price, self.course_period))

python_obj=Course(‘python開發‘,3000,‘5mons‘)
linux_obj=Course(‘linux運維‘,5000,‘3mons‘)



stu1=OldboyStudent(‘egon‘,18,‘male‘)
stu1.courses=[]
stu1.courses.append(linux_obj)
stu1.courses.append(python_obj)
stu1.courses[0].tell_course()


stu2=OldboyStudent(‘kevin‘,38,‘male‘)





  二. 封裝 :
  1. 什麽是封裝 ?
    裝,指的是把屬性裝進一個容器,
    封,指的是隱藏的意思,但是這種隱藏是對外不對內的.


  2. 為何要封裝 ?
    封裝不是單純意義的隱藏,
    
    封裝數據屬性的目的 : 將數據屬性封裝起來, 類外部的使用就無法直接操作該數據屬性了.
    需要類內部開一個接口給使用者,類的設計者可以在接口之上附加任意邏輯,從而嚴格控制使用者對屬性的操作.

    封裝函數屬性的目的 :隔離復雜度.


  3. 如何封裝 ?
    只需要在屬性前加上__開頭,該屬性就會被隱藏起來,該隱藏具備的特點 :

    1. 只是一種語法意義上的變形, 即__開頭的屬性會在檢測語法時發生變形為 _類名__屬性名的形式

    2. 這種隱藏式對外不對內的, 因為在類內部檢測語法時, 所有的代碼統一都發生了變形.
  
    3. 這種變形只在檢測語法時發生一次, 在類定義之後新增的__開頭的屬性並不會發生變形.

    4. 如果父類不想讓子類覆蓋自己的屬性, 可以在屬性前加__開頭

  註意:
    這種機制也並沒有真正意義上的限制我們從外部直接訪問屬性, 知道了類名和屬性名就可以拼出名字 :
    _類名__屬性名, 然後就可以訪問了, 如a._A__N, 即這種操作並不是嚴格意義上的限制外部訪問, 僅僅是
    一種語法意義上的變形, 主要用來限制外部的直接訪問.



  示例:
    1. 封裝數據 : 將數據隱藏起來並不是目的. 隱藏起來然後對外提供該數據的接口, 然後我們可以在接口附加上對該數據操作的
      限制, 以此完成對數據屬性操作的嚴格控制.

    
    class Teacher:
        def __init__(self,name,age):
            # self.__name=name
            # self.__age=age
            self.set_info(name,age)

        def tell_info(self):
            print(‘姓名:%s,年齡:%s‘ %(self.__name,self.__age))
        def set_info(self,name,age):
            if not isinstance(name,str):
                raise TypeError(‘姓名必須是字符串類型‘)
            if not isinstance(age,int):
                raise TypeError(‘年齡必須是整型‘)
            self.__name=name
            self.__age=age


    t=Teacher(‘egon‘,18)
    t.tell_info()

    t.set_info(‘egon‘,19)
    t.tell_info()


    2. 封裝函數 : 目的是隔離復雜度.
    
    提示 :在編程語言裏, 對外提供的接口 (接口可理為一個入口), 可以是函數, 稱為接口函數, 這與接口的概念還不一樣,
    接口代表一組接口函數的集合體.

    
    
    #取款是功能,而這個功能有很多功能組成:插卡、密碼認證、輸入金額、打印賬單、取錢
    #對使用者來說,只需要知道取款這個功能即可,其余功能我們都可以隱藏起來,很明顯這麽做
    #隔離了復雜度,同時也提升了安全性

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

    a=ATM()
    a.withdraw()


  封裝與擴展性:

    封裝在於明確區分內外, 使得類實現者可以修改封裝內的東西,而不是影響外部調用者的代碼. 而外部使用者只知道一個接口
    (函數), 只要接口(函數)名,參數不變,使用者的代碼永遠無需改變, 這就提供一個良好的合作基礎, 或者說,只要這個基礎約定
    不變,則代碼改變不足為慮




  三. 特性(property)裝飾器:

    什麽是特性property
      property是一種特殊的屬性,訪問它時會執行一段功能(函數) 然後返回值



    為什麽要用property :
      將一個類的函數定義後,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然後計算出來的,
      這種特性的使用方式遵循了統一訪問的原則


    property 下面還有裝飾器. @setter.(可以修改屬性) @deleter.(可以刪除屬性)


    示例 :
      

      BMI指數(bmi是計算而來的,但很明顯它聽起來像是一個屬性而非方法,如果我們將其做成一個屬性,更

      便於理解)

    成人的BMI數值:     過輕:低於18.5     正常:18.5-23.9     過重:24-27     肥胖:28-32     非常肥胖, 高於32       體質指數(BMI)=體重(kg)÷身高^2(m)


  
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
        @property
        def bmi(self):
            return self.weight / (self.height**2)

    p1=People(‘egon‘,75,1.85)
    print(p1.bmi)


  property 的兩種使用方法.

  
    class People:
    def __init__(self,name):
    self.__name=name

     @property
     def name(self):
     return ‘<name:%s>‘ %self.__name

     @name.setter
     def name(self,new_name):
     if type(new_name) is not str:
     print(‘名字必須是str類型‘)
     return
     self.__name=new_name

     @name.deleter
     def name(self):
     del self.__name
    
    obj=People(‘egon‘)
    print(obj.name)

    del obj.name
    print(obj.__dict__)


  

    class People:
     def __init__(self,name):
     self.__name=name

     def xxx_name(self):
     return ‘<name:%s>‘ %self.__name

     def yyy_name(self,new_name):
     if type(new_name) is not str:
     print(‘名字必須是str類型‘)
     return
     self.__name=new_name

     def zzz_name(self):
     del self.__name

     name=property(xxx_name,yyy_name,zzz_name)

    obj=People(‘egon‘)
    print(obj.name)

    del obj.name
    print(obj.__dict_




  四. 多態性.

    多態性分為靜態多態性與動態多態性.

      靜態多態性 :如任何類型都可以用運算符進行運算.

      動態多態性 : 如下
    

        peo=People()
        dog=Dog()
        pig=Pig()

        #peo、dog、pig都是動物,只要是動物肯定有talk方法
        #於是我們可以不用考慮它們三者的具體是什麽類型,而直接使用
        peo.talk()
        dog.talk()
        pig.talk()

        #更進一步,我們可以定義一個統一的接口來使用
        def func(obj):
            obj.talk()

    多態性的好處 :

      1, 增加了程序的靈活性 :
          以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用, 如func(animal)

      2, 增加了程序的可擴展性
          通過集成animal類創建了一個新的類, 使用者無需更改自己的代碼. 還是用func(animal)去調用


    示例:
      
      class Cat(Animal): #屬於動物的另外一種形態:貓
        def talk(self):
          print(‘say miao‘)
      
      def func(animal): #對於使用者來說,自己的代碼根本無需改動
        animal.talk()
      
      cat1=Cat() #實例出一只貓
      func(cat1) #甚至連調用方式也無需改變,就能調用貓的talk功能
      say miao

      這樣我們新增了一個形態Cat,由Cat類產生的實例cat1,使用者可以在完全不需要修改自己代碼的情況下。
      使用和人、狗、豬一樣的方式調用cat1的talk方法,即func(cat1)


  鴨子類型 :
  
      Python崇尚鴨子類型,即如果看起來像,叫聲像而且走起路來像鴨子, name它就是鴨子,
      python程序員通常根據這種行為來編寫程序, 例如,如果想編寫現有對象的自定義版本,可以繼承該對象也可以
      創建一個外觀和行為像,但與它無任何關系的全新對象,後者通常用於保存程序組件的松耦合度.


      示例一 :
          利用標準庫中定義的各種‘與文件類似‘的對象, 盡管這些對象的工作方式像文件,但他們沒有繼承內置文件對象的方法.


             
        #二者都像鴨子,二者看起來都像文件,因而就可以當文件一樣去用
        class TxtFile:
            def read(self):
                pass

            def write(self):
                pass

        class DiskFile:
            def read(self):
              pass
          def write(self):
              pass



      示例二. :
          其實大家一直在享受著多態性帶來的好處,比如Python的序列類型有多種形態:字符串,列表,元組. 多態性體現如下


        #str,list,tuple都是序列類型
        s=str(‘hello‘)
        l=list([1,2,3])
        t=tuple((4,5,6))

        #我們可以在不考慮三者類型的前提下使用s,l,t
        s.__len__()
        l.__len__()
        t.__len__()

        len(s)
        len(l)
        len(t

學習python課程第二十三天