零基礎學習 Python 之封裝 & 多態

寫在以前

咱們在以前說過,「封裝」「繼承」 和「多態」是 OOP 的重要特徵,前面咱們已經講過了繼承,今天咱們來學習的是 「封裝」和「多態」。這裏更多的是針對初學 Python 的讀者談談如何去理解 這倆兄弟。java

「封裝」是對具體對象的一種抽象,簡單來講就是將某些部分隱藏起來,在程序外部看不到,這個看不到不是說人用眼睛看不到那個代碼,其含義是其它的程序沒法調用。python

「多態」就如同它的名字同樣,在理解上也是「多態」的,算是各有千秋。建議各位在看完本篇文章之後,也要多 Google 一下相關的內容再加深理解。c++

封裝

想要了解封裝,就免不了要提到「私有化」。私有化就是將類或者函數中的某些屬性限制在某個區域內,從而讓外部沒法調用。bash

Python 中私有化的方法相對來講也比較簡單,就是在準備私有化的屬性或方法名字前面加上雙下滑線。咱們來看下面的例子:函數

class Sample:
   def __init__(self):
       self.my_name = 'rocky'
       self.__name = 'snow'

   def __python(self):
       print('i love python')

   def use_code(self):
       print('which is your love?')
       self.__python()

if __name__ == "__main__":
   s = Sample()
   print(s.my_name)
   print(s.__name)
複製代碼

而後咱們來運行一下,看一下結果:學習

rocky
Traceback (most recent call last):
 File "test.py", line 16, in <module>
   print(s.__name)
AttributeError: Sample instance has no attribute '__name'
複製代碼

居然報錯了,咱們查看一下報錯的信息,顯示的是咱們沒有 __name 屬性。果真前面加上雙下劃線之後就被隱藏了,在類的外面沒法被調用,咱們再來試試那個函數是否可使用,修改一下:ui

class Sample:
   def __init__(self):
       self.my_name = 'rocky'
       self.__name = 'snow'

   def __python(self):
       print('i love python')

   def use_code(self):
       print('which is your love?')
       self.__python()

if __name__ == "__main__":
   s = Sample()
   s.use_code()
   s.__python()
複製代碼

s.use_code() 的結果是要打印兩句話: 「which is your love?」 和 「i love python」,use_code() 方法和 __python() 方法是在同一個類中,能夠調用。後面的 s.__python() 試圖調用被私有化的方法,咱們運行一下來看結果:spa

which is your love?
i love python
Traceback (most recent call last):
 File "test2.py", line 16, in <module>
   s.__python()
AttributeError: Sample instance has no attribute '__python'
複製代碼

仍是報錯,告訴咱們沒有找到 __python 方法。你看,咱們是如願以償,該調用的調用,該隱藏的隱藏了。雖然用上面的方法確實的作到了「封裝」,可是若是咱們想要調用那些私有屬性的時候該怎麼辦?Python 固然給咱們想了辦法,使用 property 裝飾器。咱們來看下面的例子:code

class Sample:
   def __init__(self):
       self.my_name = 'rocky'
       self.__name = 'snow'

   @property
   def name(self):
       return self.__name

if __name__ == "__main__":
   s = Sample()
   print(s.name)
複製代碼

運行的結果以下:cdn

snow
複製代碼

從上面的結果能夠看出,用了 @property 這個裝飾器之後,在調用那個方法的時候,用的是 s.name 的形式,這就好像是在調用一個屬性同樣,跟前面例子中的 s.my_name 的格式同樣。

看來,封裝的確不是讓人 「看不見」 啊。

多態

首先讓咱們來看一個例子:

>>> 'my name is rocky'.count('m')
2
>>> [1,2,3,4,5,3].count(3)
2
複製代碼

上述例子中 count() 的做用是計數,數數某個元素在對象中出現的次數。在上面的例子裏咱們並無限定參數的類型,相似的例子還有:

>>> f = lambda x,y:x+y
複製代碼

還記得上面的上面的 lambda 函數嗎?不記得的請看Python拓展之特殊函數。

>>> f('ro','cky')
'rocky'
>>> f(2,3)
5
>>> f(['c','c++'],['java','python'])
['c', 'c++', 'java', 'python']
複製代碼

在上面的例子中咱們一樣也沒有限定參數的類型,固然了也必定不能限制,若是限制的話,那麼 Python 就失去了它最舒服的簡潔的特性。在使用的時候能夠給參數任意適合的類型,總能獲得不錯的結果。

其實以上就體現了「多態」,即同一種行爲具備不一樣的表現形式和形態的能力,也能夠說就是對象多種表現形式的體現。

固然,也有人對此提出了反對意見,由於本質上在參數傳入以前,Python 並無肯定參數的類型,因此只能讓數據進入函數以後再處理,能處理則最好,不能處理只能罷工報錯了。就像下面同樣:

>>> f('roc',2)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 1, in <lambda>
TypeError: cannot concatenate 'str' and 'int' objects
複製代碼

對於這種概念之爭就好比先有的雞仍是雞蛋之爭,因此咱們不來判斷哪一種對或者哪一種錯,這個也不是咱們本篇文章的重點,在這僅僅是把相關的信息告訴給你們。

「多態」在一些地方也被稱爲「多型」。咱們來看一下權威的《維基百科》中對此的詳細解釋:

多型(Polymorphism),是指對象導向程式執行時,相同的信息可能會送給多個不一樣的類別對象,而系統可依據物件所屬類別,引起對應類別的方法,而有不一樣的行爲。簡單來講,所謂多型意指相同的信息給予不一樣的對象會引起不一樣的動做。

簡單的說法就是有多種形式,就算不知道變量或參數所引用的對象類型,也同樣能夠進行操做,能夠說是來着不拒了。就像上面的例子那樣。

再好比,咱們以前說過的 repr() 函數,它能夠根據輸入的任意對象返回一個字符串,這個就是 「多態」 的表明之一。

>>> repr([1,2,3,4,5])
'[1, 2, 3, 4, 5]'
>>> repr(123)
'123'
>>> repr({'name':'rocky'})
"{'name': 'rocky'}"
複製代碼

使用它來實現一個小函數,依然仍是多態的表明:

>>> length('what is your name')
the length of 'what is your name' is 17
>>> length([1,2,3])
the length of '[1, 2, 3]' is 3
複製代碼

固然了,多態不是萬能的,好比像下面這樣作:

>>> length(1)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 2, in length
TypeError: object of type 'int' has no len()
複製代碼

上面的例子出錯了,出錯的願意根據錯誤提示,明確的告訴咱們 「type 'int' has no len()」。

上述的種種多態表現,全是由於 Python 是一種不須要預編譯的語言,只在運行的時候才肯定狀態(雖然最終仍是編譯了)。因此能夠這麼來講,Python 就被認爲天生是一種多態的語言。固然了也有人持有相反的觀點,認爲 Python 不支持多態,理由也是上面的說法。就好比長跑最後的一千米,有的人想就只剩一千米了,也有的人想居然還有一千米,是一個道理。

鴨子類型

咱們在前面所說的,Python 不檢查傳入的對象的類型,這種方式通俗的被稱爲「鴨子類型」,比較高端的方式是叫作「隱式類型」或者「結構式類型」。鴨子類型這個命名源於一句名言:

若是它像鴨子同樣走路,像鴨子同樣叫,那麼它就是一隻鴨子。

鴨子類型就意味着能夠向任何對象發送任何的消息,語言只關心這個對象能不能接收該消息,不會去強求該對象是否爲某一種特定的類型 —— 該對象的多態表現。

多態的介紹大概就是這些,對於Python 多態之間的爭論咱們看看就好,不要太過於在乎,咱們只要明白了咱們該明白的就好。

寫在最後

更多內容,歡迎關注公衆號「Python空間」,期待和你的交流。

在這裏插入圖片描述
相關文章
相關標籤/搜索