天天看點

python面向對象多态的了解_python的面向對象的特性(繼承、封裝、多态)

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

多态: 可對不同類的對象使用同樣的操作。

封裝:對外部世界隐藏對象的工作細節。

繼承:以普通的類為基礎建立專門的類對象。

多态

面向對象程式設計最有趣的特性是多太,它是是讓大多數人犯暈的特性。是以,先來介紹這個。

多态意思是“有多種形式”。多态意味着就算不知道變量所引用的對象類是什麼,還是能對它進行操作,而它也會根據對象(或類)類型的不同而表現出不同的行為。

從最簡單的開始

任何不知道對象到底是什麼類型,但是又要對對象“做點什麼”的時候,都會用到多态。這不僅限于方法----很多内建運算符和函數都有多态的性質,考慮下面這個例子:

>>> 1 + 2

3

>>> 'fish' + 'license'

'fishlicense'

複制代碼

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

>>> def add(x,y):

return x+y

>>> add(1,2)

>>> add('hello.','world')

'hello.world'

複制代碼

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

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

>>> def length_message(x):

print"The length of " , repr(x),"is",len(x)

>>> length_message('chongshi')

The length of  'chongshi' is 8

>>> length_message([1,2,3])

The length of  [1, 2, 3] is 3

複制代碼

len函數用于計算長度,repr用于放置函數的内容;repr函數是多态特性的代表之一---可以對任何東西使用。

很多函數和運算符都是多态的,你寫的絕大多數程式可能都是,即便你并非有意這樣。

封裝

封裝是對全局作用域中其它區域隐藏多餘資訊的原則。

封裝聽起來有些像多态,因為他們都是 抽象的原則---他們都會幫助處理程式元件而不用過多關心多餘細節,就像函數做的一樣。

但是封裝并不等同于多态。多态的可以讓使用者對于不知道是什麼類(或對象類型)的對象進行方法調用,而封裝是可以不用關心對象是如何建構的而直接進行使用。

建立一個有對象(通過像調用函數一樣調用類)後,将變量c綁定到該對象上。可以使用setName 和 getName 方法(假設已經有)

>>> c = closedObject()

>>> c.setName('sir lancelot')

>>> c.getName()

‘sir lancelot’

複制代碼

繼承

我們不想把同一段代碼寫好幾,之前使用的函數避免了這種情況。但現在又有個更微妙的問題。如果已經有了一個類,又想建立一個非常類似的類,隻是添加幾個方法。

比如有動物類,我們又想在動物類的基礎上建立鳥類、魚類,哺乳動物類。

上面這些特性會根據後面的學習來深入的了解。

================================

建立自己的類

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

_metaclass_ = type #确定新式類

class Person:

def setName(self,name):

self.name = name

def getName(self):

return self,name

def greet(self):

print "Hello, world! I'm %s" %self.name

複制代碼

注意:新式類的文法中,需要在子產品或者腳本開始的地方放置指派語句_metaclass_ = type 。

建立了一個Person的類,這個類包含了三個方法定義,隻是那個self看起有點奇怪,它是對于對象自身的引用。

讓我們建立執行個體看看:

>>> huhu = Person()

>>> huhu.setName('hu zhiheng')

>>> huhu.greet()

Hello, world! I'm hu zhiheng

複制代碼

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

和之前一樣,特性也可以在外部通路:

>>> huhu.name

'hu zhiheng'

>>> huhu.name = 'yoda'

>>> huhu.greet()

Hello, world! I'm yoda

複制代碼

特性、函數和方法

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

>>> class Class:

def method(self):

print 'I have a self!'

>>> def function():

print "I don't"

>>> instance = Class()

>>> instance.method()

I have a self!

>>> instance.method = function

>>> instance.method()

I don't

複制代碼

self參數并不取決于調用方法的方式,目前使用的是執行個體調用方法,可以随意使用引用同一個方法的其他變量:

>>> class Bird:

song =  'Squaawk!'

def sing(self):

print self.song

>>> bird = Bird()

>>> bird.sing()

Squaawk!

>>> birdsong = bird.sing

>>> birdsong()

Squaawk!

複制代碼

指定超類

子類可以擴充超類的定義。将其他類名寫在class語句後的圓括号内可以指定超類:

class Filter:

def init(self):

self.blocked = []

def filter(self , sequence):

return [x for x in sequence if x not in self.blocked]

class SPAMFilter(Filter):  #SPAMFilter是Filter的子類

def init(self):        #重寫Filter類中的init方法

self.blocked = ['SPAM']

複制代碼

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

>>> f = Filter()

>>> f.init()

>>> f.filter([1,2,3])

[1, 2, 3]

複制代碼

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

>>> s = SPAMFilter()

>>> s.init()

>>> s.filter(['SPAM','SPAMD','SPAM','HELLO','WORLD','SPAM'])

['SPAMD', 'HELLO', 'WORLD']

複制代碼

調查繼承

如果想要檢視一個類是否是另一個的子類。可以使用内建的issubclass函數:

>>> issubclass(SPAMFilter, Filter)

True

>>> issubclass(Filter,SPAMFilter)

False