<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 面向?qū)ο缶幊?上篇)

          共 8608字,需瀏覽 18分鐘

           ·

          2020-07-28 18:38


          我的施工計劃圖

          已完成專題包括:

          1我的施工計劃

          2數(shù)字專題

          3字符串專題

          4列表專題

          5流程控制專題

          6編程風格專題

          7函數(shù)使用專題

          今天是面向?qū)ο缶幊痰纳掀夯A(chǔ)專題

          Python 面向?qū)ο缶幊?/span>

          面向?qū)ο蟪绦蛟O(shè)計思想,首先思考的不是程序執(zhí)行流程,它的核心是抽象出一個對象,然后構(gòu)思此對象包括的數(shù)據(jù),以及操作數(shù)據(jù)的行為方法。

          本專題主要討論面向?qū)ο缶幊?OOP)的基礎(chǔ)和進階知識,實際開發(fā)模型中OOP的主要實踐,盡量使用最貼切的例子。

          基礎(chǔ)專題

          1 類定義

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

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

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

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

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

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

          結(jié)果顯示它是Animal對象,其實打印結(jié)果顯示實例屬性信息會更友好,那么怎么實現(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類定義基礎(chǔ)上,再添加一個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屬性呢?使用內(nèi)置函數(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類內(nèi)的所有方法引用,如被方法getFeedingTime方法引用。但是,不能被其他類引用。

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

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

          xiaoming.recordTime()

          就會報沒有__speed屬性的異常,從而驗證了__speed屬性已經(jīng)變?yōu)轭悆?nèi)私有,不會暴露在外面。

          總結(jié):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)

          打印結(jié)果:

          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分支,從軟件設(shè)計角度講,這種不斷破壞封裝的行為不可取。

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

          首先,在基類Animal中創(chuàng)建一個基類方法,然后CatBird分別重寫此方法,最后傳入到Manager類的animal參數(shù)是什么類型,在recordTime方法中就會對應調(diào)用這個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邏輯,只需要調(diào)用我們定義的Animal類的基方法getSpeedBehavior即可。

          在使用上面所有類時,Manager(jiafeimao)傳入Cat類實例時,recordTime方法調(diào)用就被自動指向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()??

          總結(jié)

          以上就是面向?qū)ο缶幊虒n}的基礎(chǔ)部分,大綱如下:

          • Python 面向?qū)ο缶幊?/p>

          • 基礎(chǔ)專題

            • 1 類定義

            • 2 實例

            • 3 打印實例

            • 4 屬性

            • 5 private,protected,public

            • 6 繼承

            • 7 多態(tài)

          • 總結(jié)

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

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

          機器學習:算法視角



          長按下方二維碼

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

          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级片日韩亚洲 | 天堂在线免费视频 | 亚洲日韩发布在线免费 | 有码精品一区二区 | 人妻少妇精品视频二区奶水乛 |