python的面向對象的特性(繼承、封裝、多態)


創建自已對象就python非常核心的概念,事實上,python被稱為面向對象語言,本章會介紹如何創建對象。以及面向對象的概念:繼承、封裝、多態。

多態: 可對不同類的對象使用同樣的操作。
封裝:對外部世界隱藏對象的工作細節。
繼承:以普通的類為基礎建立專門的類對象。


多態
面向對象程序設計最有趣的特性是多太,它是是讓大多數人犯暈的特性。所以,先來介紹這個。
多態意思是“有多種形式”。多態意味着就算不知道變量所引用的對象類是什么,還是能對它進行操作,而它也會根據對象(或類)類型的不同而表現出不同的行為。

從最簡單的開始
  任何不知道對象到底是什么類型,但是又要對對象“做點什么”的時候,都會用到多態。這不僅限於方法----很多內建運算符和函數都有多態的性質,考慮下面這個例子:

  1. >>> 1 + 2
  2. 3
  3. >>> 'fish' + 'license'
  4. 'fishlicense'
復制代碼

這里的加運算符對於數字(本例中為整數)和字符串(以及其他類型的序列)都能起作用。假設有個叫做add的函數,它可以將兩個對象相加。那么可以直接將其定義成上面的形式,對於很多類型的參數都可以用,如下:

  1. >>> def add(x,y):
  2.     return x+y

  3. >>> add(1,2)

  4. >>> add('hello.','world')
  5. 'hello.world'
復制代碼

看起來有點傻,但是關鍵在於參數可以是任何支持加法的對象。

如果需要編寫打印對象長度消息的函數,則只需對象具有長度(len函數可用)即可。

  1. >>> def length_message(x):
  2.     print"The length of " , repr(x),"is",len(x)

  3.    
  4. >>> length_message('chongshi')
  5. The length of  'chongshi' is 8
  6. >>> length_message([1,2,3])
  7. The length of  [1, 2, 3] is 3
復制代碼

len函數用於計算長度,repr用於放置函數的內容;repr函數是多態特性的代表之一---可以對任何東西使用。
很多函數和運算符都是多態的,你寫的絕大多數程序可能都是,即便你並非有意這樣。


封裝

封裝是對全局作用域中其它區域隱藏多余信息的原則。
封裝聽起來有些像多態,因為他們都是 抽象的原則---他們都會幫助處理程序組件而不用過多關心多余細節,就像函數做的一樣。
但是封裝並不等同於多態。多態的可以讓用戶對於不知道是什么類(或對象類型)的對象進行方法調用,而封裝是可以不用關心對象是如何構建的而直接進行使用。
創建一個有對象(通過像調用函數一樣調用類)后,將變量c綁定到該對象上。可以使用setName 和 getName 方法(假設已經有)

  1. >>> c = closedObject()
  2. >>> c.setName('sir lancelot')
  3. >>> c.getName()
  4. ‘sir lancelot’
復制代碼

繼承
我們不想把同一段代碼寫好幾,之前使用的函數避免了這種情況。但現在又有個更微妙的問題。如果已經有了一個類,又想建立一個非常類似的類,只是添加幾個方法。
比如有動物類,我們又想在動物類的基礎上建立鳥類、魚類,哺乳動物類。

上面這些特性會根據后面的學習來深入的理解。
================================


創建自己的類

終於可以創建自己的類了,先來看一個簡單的類:

  1. _metaclass_ = type #確定新式類

  2. class Person:
  3.     def setName(self,name):
  4.         self.name = name

  5.     def getName(self):
  6.         return self,name

  7.     def greet(self):
  8.         print "Hello, world! I'm %s" %self.name
復制代碼

注意:新式類的語法中,需要在模塊或者腳本開始的地方放置賦值語句_metaclass_ = type 。

創建了一個Person的類,這個類包含了三個方法定義,只是那個self看起有點奇怪,它是對於對象自身的引用。
讓我們創建實例看看:

  1. >>> huhu = Person()
  2. >>> huhu.setName('hu zhiheng')
  3. >>> huhu.greet()
  4. Hello, world! I'm hu zhiheng
復制代碼

應該能說明self的用處了,在調用huhu的setName 和 greet 函數時,huhu自動將自己作為第一個參數傳入函數中----因此形象地命名為self。每個人可能都會有自己的叫法,但是因為它總是對象自身,所以習慣上總是叫做self 。

和之前一樣,特性也可以在外部訪問:

  1. >>> huhu.name
  2. 'hu zhiheng'
  3. >>> huhu.name = 'yoda'
  4. >>> huhu.greet()
  5. Hello, world! I'm yoda
復制代碼

特性、函數和方法

self 參數事實上正是方法和函數的區別。方法將它們的第一個參數綁定到所屬的實例上,因此這個參數可以不必提供。所以可以將特性綁定到一個普通函數上,這樣就不會有特殊的self參數了:

  1. >>> class Class:
  2.     def method(self):
  3.         print 'I have a self!'

  4.         
  5. >>> def function():
  6.     print "I don't"

  7.    
  8. >>> instance = Class()
  9. >>> instance.method()
  10. I have a self!
  11. >>> instance.method = function
  12. >>> instance.method()
  13. I don't
復制代碼

self參數並不取決於調用方法的方式,目前使用的是實例調用方法,可以隨意使用引用同一個方法的其他變量:

  1. >>> class Bird:
  2.     song =  'Squaawk!'
  3.     def sing(self):
  4.         print self.song

  5.         
  6. >>> bird = Bird()
  7. >>> bird.sing()
  8. Squaawk!
  9. >>> birdsong = bird.sing
  10. >>> birdsong()
  11. Squaawk!
復制代碼

指定超類

子類可以擴展超類的定義。將其他類名寫在class語句后的圓括號內可以指定超類:

  1. class Filter:
  2.     def init(self):
  3.         self.blocked = []
  4.     def filter(self , sequence):
  5.         return [x for x in sequence if x not in self.blocked]

  6. class SPAMFilter(Filter):  #SPAMFilter是Filter的子類
  7.     def init(self):        #重寫Filter類中的init方法
  8.         self.blocked = ['SPAM']
復制代碼

Filter 是個用於過濾序列的通用類,事實上它不能過濾任何東西:

  1. >>> f = Filter()
  2. >>> f.init()
  3. >>> f.filter([1,2,3])
  4. [1, 2, 3]
復制代碼

Filter 類的用戶在於它可以用作其他類的基類(超類,“java中叫父類”),比如SPAMFilter類,可以將序列中的“SPAM”過濾出來。

  1. >>> s = SPAMFilter()
  2. >>> s.init()
  3. >>> s.filter(['SPAM','SPAMD','SPAM','HELLO','WORLD','SPAM'])
  4. ['SPAMD', 'HELLO', 'WORLD']
復制代碼

調查繼承

如果想要查看一個類是否是另一個的子類。可以使用內建的issubclass函數:

  1. >>> issubclass(SPAMFilter, Filter)
  2. True
  3. >>> issubclass(Filter,SPAMFilter)
  4. False


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM