1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Python 面向對象編程(上篇)

        共 8608字,需瀏覽 18分鐘

         ·

        2020-07-28 18:38


        我的施工計劃圖

        已完成專題包括:

        1我的施工計劃

        2數(shù)字專題

        3字符串專題

        4列表專題

        5流程控制專題

        6編程風格專題

        7函數(shù)使用專題

        今天是面向對象編程的上篇:基礎專題

        Python 面向對象編程

        面向對象程序設計思想,首先思考的不是程序執(zhí)行流程,它的核心是抽象出一個對象,然后構思此對象包括的數(shù)據(jù),以及操作數(shù)據(jù)的行為方法。

        本專題主要討論面向對象編程(OOP)的基礎和進階知識,實際開發(fā)模型中OOP的主要實踐,盡量使用最貼切的例子。

        基礎專題

        1 類定義

        動物是自然界一個龐大的群體,以建模動物類為主要案例論述OOP編程。

        Python語言創(chuàng)建動物類的基本語法如下,使用class關鍵字定義一個動物類:

        class?Animal():
        ????pass

        類里面可包括數(shù)據(jù),如下所示的Animal類包括兩個數(shù)據(jù):self.nameself.speed

        class?Animal():
        ???def?__init__(self,name,speed):
        ???????self.name?=?name?#?動物名字
        ???????self.speed?=?speed?#?動物行走或飛行速度

        注意到類里面通過系統(tǒng)函數(shù)__init__為類的2個數(shù)據(jù)賦值,數(shù)據(jù)前使用self保留字。

        self的作用是指名這兩個數(shù)據(jù)是實例上的,而非類上的。

        同時注意到__init__方法的第一個參數(shù)也帶有self,所以也表明此方法是實例上的方法。

        2 實例

        理解什么是實例上的數(shù)據(jù)或方法,什么是類上的數(shù)據(jù),需要先建立實例的概念,的概念,如下:

        #?生成一個名字叫加菲貓、行走速度8km/h的cat對象
        cat?=?Animal('加菲貓',8)?

        cat就是Animal的實例,也可以一次創(chuàng)建成千上百個實例,如下創(chuàng)建1000只蜜蜂:

        bees?=?[Animal('bee'+str(i),5)?for?i?in?range(1000)]

        總結:自始至終只使用一個類Animal,但卻可以創(chuàng)建出許多個它的實例,因此是一對多的關系。

        實例創(chuàng)建完成后,下一步打印它看看:

        In?[1]:?print(cat)???????????????????????????????????????????????????????????
        <__main__.Animal?object?at?0x7fce3a596ad0>

        結果顯示它是Animal對象,其實打印結果顯示實例屬性信息會更友好,那么怎么實現(xiàn)呢?

        3 打印實例

        只需重新定義一個系統(tǒng)(又稱為魔法)函數(shù)__str__ ,就能讓打印實例顯示的更加友好:

        class?Animal():
        ???def?__init__(self,name,speed):
        ???????self.name?=?name?#?動物名字
        ???????self.speed?=?speed?#?動物行走或飛行速度
        ??
        ???def?__str__(self):
        ????????return?'''Animal({0.name},{0.speed})?is?printed
        ????????????????name={0.name}
        ????????????????speed={0.speed}'''
        .format(self)

        使用0.數(shù)據(jù)名稱的格式,這是類專有的打印格式。

        現(xiàn)在再打印:

        cat?=?Animal('加菲貓',8)
        print(cat)

        打印信息如下:

        Animal(加菲貓,8)?is?printed
        ????????????????name=加菲貓
        ????????????????speed=8

        以上就是想要的打印格式,看到實例的數(shù)據(jù)值都正確。

        4 屬性

        至此,我們都稱類里的namespeed稱為數(shù)據(jù),其實它們有一個專業(yè)名稱:屬性。

        同時,上面還有一個問題我們沒有回答完全,什么是類上的屬性?

        如下,在最新Animal類定義基礎上,再添加一個cprop屬性,它前面沒有self保留字:

        class?Animal():
        ???cprop?=?"我是類上的屬性cprop"
        ???
        ???def?__init__(self,name,speed):
        ???????self.name?=?name?#?動物名字
        ???????self.speed?=?speed?#?動物行走或飛行速度
        ??
        ???def?__str__(self):
        ????????return?'''Animal({0.name},{0.speed})?is?printed
        ????????????????name={0.name}
        ????????????????speed={0.speed}'
        ''.format(self)

        類上的屬性直接使用類便可引用:

        In?[1]:?Animal.cprop???????????????????????????????????????????????????????????
        Out[1]:?'我是類上的屬性cprop'

        類上的屬性,實例同樣可以引用,并且所有的實例都共用此屬性值:

        In?[1]:?cat?=?Animal('加菲貓',8)
        In?[2]:?cat.cprop??????????????????????????????????????????????????????????????
        Out[2]:?'我是類上的屬性cprop'

        Python作為一門動態(tài)語言,支持屬性的動態(tài)添加和刪除。

        如下cat實例原來不存在color屬性,但是賦值時不光不會報錯,相反會直接將屬性添加到cat上:

        cat.color?=?'grap'

        那么,如何驗證cat是否有color屬性呢?使用內置函數(shù)hasattr

        In?[24]:?hasattr(cat,'color')?#?cat?已經(jīng)有`color`屬性??????????????????????????
        Out[24]:?True

        但是注意:以上添加屬性方法僅僅為cat實例本身添加,而不會為其他實例添加:

        In?[26]:?monkey?=?Animal('大猩猩',2)????????????????????????????????????????????
        In?[27]:?hasattr(monkey,'color')?????????????????????????????????????????????
        Out[27]:?False

        monkey實例并沒有color屬性,注意與__init__創(chuàng)建屬性方法的區(qū)別。

        5 private,protected,public

        namespeed屬性,引用此實例的對象都能訪問到它們,如下:

        #?模塊名稱:manager.py

        import?time

        class?Manager():
        ????def?__init__(self,animal):
        ????????self.animal?=?animal
        ????????
        ????def?recordTime(self):
        ????????self.__t?=?time.time()
        ????????print('feeding?time?for?%s(行走速度為:%s)?is?%.0f'%(self.animal.name,self.animal.speed,self.__t))
        ????
        ????def?getFeedingTime(self):
        ????????return?'%0.f'%(self.__t,)?

        使用以上Manager類,創(chuàng)建一個cat實例,xiaoming實例引用cat:

        cat?=?Animal('加菲貓',8)
        xiaoming?=??Manager(cat)?

        xiaomingrecordTime方法引用里,引用了animal的兩個屬性namespeed:

        In[1]:?xiaoming.recordTime()

        Out[1]:?feeding?time?for?加菲貓(行走速度為:8)?is?1595681304

        注意看到self.__t屬性,它就是一個私有屬性,只能被Manager類內的所有方法引用,如被方法getFeedingTime方法引用。但是,不能被其他類引用。

        如果我們連speed這個屬性也不想被其他類訪問,那么只需將self.speed修改為self.__speed:

        同時Manager類的self.animal.speed修改為self.animal.__speed,再次調用下面方法時:

        xiaoming.recordTime()

        就會報沒有__speed屬性的異常,從而驗證了__speed屬性已經(jīng)變?yōu)轭悆人接校粫┞对谕饷妗?/p>

        總結:name屬性相當于java的public屬性,而__speed相當于java的private屬性。

        下面在說繼承時,講解protected屬性,實際上它就是帶有1個_的屬性,它只能被繼承的類所引用。

        6 繼承

        上面已經(jīng)講完了OOP三大特性中的封裝性,而繼承是它的第二大特性。子類繼承父類的所有publicprotected數(shù)據(jù)和方法,極大提高了代碼的重用性。

        如上創(chuàng)建的Animal類最新版本為:

        class?Animal():
        ???cprop?=?"我是類上的屬性cprop"
        ???
        ???def?__init__(self,name,speed):
        ???????self.name?=?name?#?動物名字
        ???????self.__speed?=?speed?#?動物行走或飛行速度
        ??
        ???def?__str__(self):
        ????????return?'''Animal({0.name},{0.__speed})?is?printed
        ????????????????name={0.name}
        ????????????????speed={0.__speed}'''
        .format(self)

        現(xiàn)在有個新的需求,要重新定義一個Cat貓類,它也有namespeed兩個屬性,同時還有colorgenre兩個屬性,打印時只需要打印namespeed兩個屬性就行。

        因此,基本可以復用基類Animal,但需要修改__speed屬性為受保護(protected)的_speed屬性,這樣子類都可以使用此屬性,而外部還是訪問不到它。

        綜合以上,Cat類的定義如下:

        class?Cat(Animal):
        ????def?__init__(self,name,speed,color,genre):
        ????????super().__init__(name,speed)
        ????????self.color?=?color?
        ????????self.genre?=?genre

        首先使用super()方法找到Cat的基類Animal,然后引用基類的__init__方法,這樣復用基類的方法。

        使用Cat類,打印時,又復用了基類的 __str__方法:

        jiafeimao?=?Cat('加菲貓',8,'gray','CatGenre')
        print(jiafeimao)

        打印結果:

        Animal(加菲貓,8)?is?printed
        ????????????????name=加菲貓
        ????????????????speed=8

        以上就是基本的繼承使用案例,繼承要求基類定義的數(shù)據(jù)和行為盡量標準、盡量精簡,以此提高代碼復用性。

        7 多態(tài)

        如果說OOP的封裝和繼承使用起來更加直觀易用,那么作為第三大特性的多態(tài),在實踐中真正運用起來就不那么容易。有的讀者OOP編程初期,可能對多態(tài)的價值體會不深刻,甚至都已經(jīng)淡忘它的存在。

        那么問題就在:多態(tài)到底真的有用嗎?到底使用在哪些場景?

        多態(tài)價值很大,使用場景很多,幾乎所有的系統(tǒng)或軟件,都能看到它的應用。這篇文章盡可能通過一個精簡的例子說明它的價值和使用方法。如果不用多態(tài),方法怎么寫;使用多態(tài),又是怎么寫。

        為了一脈相承,做到一致性,仍然基于上面的案例,已經(jīng)創(chuàng)建好的Cat類要有一個方法打印和返回它的爬行速度。同時需要再創(chuàng)建一個類Bird,要有一個方法打印和返回它的飛行速度;

        如果不使用多態(tài),為Cat類新增一個方法:

        class?Cat(Animal):
        ????def?__init__(self,name,speed,color,genre):
        ????????super().__init__(name,speed)
        ????????self.color?=?color?
        ????????self.genre?=?genre
        ????#?添加方法
        ????def?getRunningSpeed(self):
        ????????print('running?speed?of?%s?is?%s'?%(self.name,?self._speed))
        ????????return?self._speed

        重新創(chuàng)建一個Bird類:

        class?Bird(Animal):
        ????def?__init__(self,name,speed,color,genre):
        ????????super().__init__(name,speed)
        ????????self.color?=?color?
        ????????self.genre?=?genre
        ????#?添加方法
        ????def?getFlyingSpeed(self):
        ????????print('flying?speed?of?%s?is?%s'?%(self.name,?self._speed))
        ????????return?self._speed

        最后,上面創(chuàng)建的Manager類會引用CatBird類,但是需要修改recordTime方法,因為Cat它是爬行的,Bird它是飛行的,所以要根據(jù)對象類型的不同做邏輯區(qū)分,如下所示:

        #?模塊名稱:manager.py

        import?time
        from?animal?import?(Animal,Cat,Bird)

        class?Manager():
        ????def?__init__(self,animal):
        ????????self.animal?=?animal
        ????????
        ????def?recordTime(self):
        ????????self.__t?=?time.time()
        ????????if?isinstance(self.animal,?Cat):
        ????????????print('feeding?time?for?%s?is?%.0f'%(self.animal.name,self.__t))
        ????????????self.animal.getRunningSpeed()
        ????????if?isinstance(self.animal,Bird):
        ????????????print('feeding?time?for?%s?is?%.0f'%(self.animal.name,self.__t))
        ????????????self.animal.getFlyingSpeed()

        ????def?getFeedingTime(self):
        ????????return?'%0.f'%(self.__t,)?

        如果再來一個類,我們又得需要修改recordTime,再增加一個if分支,從軟件設計角度講,這種不斷破壞封裝的行為不可取。

        但是,使用多態(tài),就可以保證recordTime不被修改,不必寫很多if分支。怎么來實現(xiàn)呢?

        首先,在基類Animal中創(chuàng)建一個基類方法,然后CatBird分別重寫此方法,最后傳入到Manager類的animal參數(shù)是什么類型,在recordTime方法中就會對應調用這個animal實例的方法,這就是多態(tài)

        代碼如下:

        animal2.py 模塊如下:

        #?animal2.py?模塊

        class?Animal():
        ???cprop?=?"我是類上的屬性cprop"
        ???
        ???def?__init__(self,name,speed):
        ???????self.name?=?name?#?動物名字
        ???????self._speed?=?speed?#?動物行走或飛行速度
        ??
        ???def?__str__(self):
        ????????return?'''Animal({0.name},{0._speed})?is?printed
        ????????????????name={0.name}
        ????????????????speed={0._speed}'''
        .format(self)

        ???def?getSpeedBehavior(self):
        ???????pass?

        class?Cat(Animal):
        ????def?__init__(self,name,speed,color,genre):
        ????????super().__init__(name,speed)
        ????????self.color?=?color?
        ????????self.genre?=?genre
        ????????
        ????#?重寫方法
        ????def?getSpeedBehavior(self):
        ????????print('running?speed?of?%s?is?%s'?%(self.name,?self._speed))
        ????????return?self._speed
        ????????

        class?Bird(Animal):
        ????def?__init__(self,name,speed,color,genre):
        ????????super().__init__(name,speed)
        ????????self.color?=?color?
        ????????self.genre?=?genre

        ????#?重寫方法
        ????def?getSpeedBehavior(self):
        ????????print('flying?speed?of?%s?is?%s'?%(self.name,?self._speed))
        ????????return?self._speed

        manager2.py 模塊如下:

        #?manager2.py?模塊

        import?time
        from?animal2?import?(Animal,Cat,Bird)

        class?Manager():
        ????def?__init__(self,animal):
        ????????self.animal?=?animal
        ????????
        ????def?recordTime(self):
        ????????self.__t?=?time.time()
        ????????print('feeding?time?for?%s?is?%.0f'%(self.animal.name,self.__t))
        ????????self.animal.getSpeedBehavior()

        ????def?getFeedingTime(self):
        ????????return?'%0.f'%(self.__t,)??

        recordTime方法非常清爽,不需要任何if邏輯,只需要調用我們定義的Animal類的基方法getSpeedBehavior即可。

        在使用上面所有類時,Manager(jiafeimao)傳入Cat類實例時,recordTime方法調用就被自動指向Cat實例的getSpeedBehavior方法;

        Manager(haiying)傳入Bird類實例時,自動指向Bird實例的getSpeedBehavior方法,這就是多態(tài)和它的價值,Manager類的方法不必每次都修改,保證了類的封裝性。


        if?__name__?==?"__main__":
        ????jiafeimao?=?Cat('jiafeimao',2,'gray','CatGenre')
        ????haiying?=?Bird('haiying',40,'blue','BirdGenre')

        ????Manager(jiafeimao).recordTime()
        ????print('#'*30)
        ????Manager(haiying).recordTime()??

        總結

        以上就是面向對象編程專題的基礎部分,大綱如下:

        • Python 面向對象編程

        • 基礎專題

          • 1 類定義

          • 2 實例

          • 3 打印實例

          • 4 屬性

          • 5 private,protected,public

          • 6 繼承

          • 7 多態(tài)

        • 總結

        感謝華章出版社對原創(chuàng)文章的大力支持,贈送3本機器學習:算法視角(原書第2版)》,機器學習領域暢銷教材知名媒體推薦的十大機器學習入門教材之一,作者都是名校教授大咖。

        中獎讀者綜合考慮留言質量,參與度和贊賞情況,29日回復中獎留言。長按下方二維碼查看此書詳情,明天京東有滿減活動。

        機器學習:算法視角



        長按下方二維碼

        全文4000多字,100%用心原創(chuàng)作品。歡迎點贊、在看和轉發(fā)支持,這樣我會更有動力寫好下一篇OOP編程的進階部分,謝謝。

        瀏覽 38
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            美操逼 | 亚洲综合一区二区 | 国产传媒成人 | 香港三日本8a三级少妇三级99 | 最新超碰上传 | 久久久久久久久久久免费视频 | 成人做爱在线W视频 | 人人想人人操 | 四虎影院永久 | 国产视频1234区 |