摘要
經過前面的學習我們已經掌握了內建對象類型(函數 字符串 列表 元祖 字典)
以及內建函數和標準庫的用法,還有定義函數的方法 。
next We are will Study 創建自己的對象(自定義對象)
類型或者叫做類的對象》》這是Python非常核心的概念。As we all known
Python 被稱爲面向對象的語言(SmallTalk 、C++、 Java、)
接下來 我們會介紹如何創建對象,以及多態、封裝、方法、特性、超類以及繼承的概念。
新知識很多,Now We Are Starting .
=========================================================================
對象最重要的優點:
多態:
意味着可以對不同類的對象使用相同的操作。
封裝
對外部世界隱藏對象的工作細節
繼承
以通用的類爲基礎建立專門的類的對象
術語:多態來自希臘語,意思是“有多種形式”。
多態意味着就算不知道變量所引用的對象類型是什麼,還是能對它進行操作,而它也會根據對象(或類)類型的不同而表現出不同的行爲。
- 讓對象自己進行操作
多態和方法
綁定到對象特性上面的函數稱爲方法(method),
封裝
可以不用關心對象是如何構建的而直接進行使用。
繼承
它是另外一個懶惰(褒義)的行爲。程序員不想把同一段代碼輸入好幾次,
類和類型
類爲種類或類型的同義詞。從很多方面來說,這就是類—一種對象。
所有的對象都屬於一個類,稱爲類的實列(instance)。
鳥類(所有鳥的集合)具有很多子類(百靈鳥類)子類(subclass)
故:鳥類爲百靈鳥類的超類(Superclass)
在面向對象程序設計中,子類的關係是隱式的,因爲一個類的定義取決於它所支持的方法。
類的所有(instance)都會包含這些方法,所以所有子類的所有實列都有這些方法。
定義子類:
只是個定義更多(也有可能是重載已經存在的方法的過程)。
Eg:
Bird(可能支持fly方法),而企鵝類(Penguin)可能會增加個Eatfish的方法。
當創建penguin類時。可能會想重寫(override)超類的fly方法。對於penguin的實列來說,
這個方法要麼什麼也不做,要麼就產生異常(因爲企鵝不會飛)。
區別
在舊版本的python中,內奸的對象是基於類型的,自定義的對象則是基於類的。可以創建類但是不可以創建類型。
最近版本的Python中,遊樂一定變化,基本類型和類之間的界限開始模糊了。可以創建內建類型的子類,而這些類型的行爲更類似於類。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
創建自己的類
先來看一個簡單的類!!
_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_=typepyth
3.0之後已不存在舊式類。
接下來讓我們創建一些實列看看:
foo=Person()
bar=Person()
foo.setName('ChengKaoAo')
bar.setName('MeiXuanZheng')
···
>特性、函數和方法
self參數事實上正是方法和函數的區別:
方法(更專業一點可以成爲綁定方法)將它們的第一個參數綁定到所屬的實列上,因此你無需顯示提供參數。當然你也可以將特性綁定到一個普通函數上,這樣就不會有特殊的self參數了。
再論私有化
默認情況下,程序可以從外部訪問一個對象特性。
爲了讓方法或者特性變爲私有(從外部無法訪問),只要在它的名字前面加上雙下劃線即可:
class Secretive:
def __inaccessible(self):
print "Bet you can't see me..."
def accessible(self):
print "The secret message is:"
self.__inaccessible()
s = Secretive()
s.accessible()
類的命名和空間
所有位於class語句中的代碼都在特殊命名空間執行——類命名空間。這個命名空間可由類內所有成員訪問。並不是所有python程序員都知道類的定義其實就是執行代碼塊
這一點非常有用,比如在類的定義區並不只限定只能使用def語句:
class C:
print ('Class C being defined:')
#繼續>>>
class MemberCounter:
members=0
def init(self):
MemberCounter.menbers+=1
指定超類
子類可以擴展超類的定義。將其他類名寫在class語句後的圓括號內可以指定超類:
#_*_ coding:utf8 _*_
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']
f = Filter()
f.init()
print f.filter([1,2,3])
s = SPAMFilter()
s.init()
print s.filter(['SPAM','SPAM','SPAM','SPAM','eggs','bacon','SPAM'])
Run Result:
這裏用提供新定義的方式重寫了Filter的init定義。
filter方法的定義是從Filter類中拿過來的,所以不用重寫它的定義。
第二個要點就是揭示了繼承的用處:我們可以寫一大堆不同的過濾類,全都從Filter繼承,每一個我都可以使用已經實現的filter方法。
檢查繼承
如果想要查看一個類是否是否是另一個的子類,可以使用內建的issubclass函數:
# _*_ coding:utf8 _*_
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']
print issubclass(SPAMFilter, Filter)
print issubclass(Filter, SPAMFilter)
The Run Result
多個超類
一個類地基類可能會多於一個,EG:
子類(TalkingCalculator)自己不做任何事,它從自己的超類繼承所有的行爲。
它從Calculator類哪裏繼承Calculate方法,從Talke類哪裏繼承talk方法,這樣它就成了會說話的
計算器(talking calculator)
這種行爲叫做多重繼承。除非非常熟悉,否則應儘量避免使用,因爲有時會出現不可預見的麻煩,
# _*_ coding:utf8 _*_
class Calculator:
def calculate(self,expression):
self.value = eval(expression)
class Talker:
def talk(self):
print 'Hi,my value is',self.value
class TalkingCalculator(Calculator, Talker):
pass
tc = TalkingCalculator()
tc.calculate('1+2*3+1')
tc.talk()
當有2個相同名字的不同方法時,需要注意超類的順序(在Class語句中),先繼承的類中的方法會重寫後繼承的類中的方法,
接口和內省
“接口”的概念與多態有關。
在處理多態對象時,只要關心他的接口(或稱“協議”)即可,也就是公開的方法和特徵。
在Python中,不用顯式地指定對象必須包含哪些方法才能作爲參數接收。
一般來說只需要讓對象符合當前的接口(就是實現當前的方法),但是還可以更靈活一些。
除了調用方法然後期待一切順利之外,還可檢查所需方法是否已經存在。
關於面向對象的思考
要點:
將屬於一類的對象放在一起。如果一個函數操縱一個全局變量,那麼兩者最好都在類內作爲特徵和方法出現。
不要讓對象過於親密。方法應該只關心自己實例的特徵。讓其他實例管理自己的狀態。
- 要小心繼承,尤其是多重繼承。繼承機制有時很有用,但也會在某些情況下讓事情變得過於複雜。多繼承難以正確使用,更難以調試。
- 簡單就好。讓你的方法小巧。一般來說,多數方法都應該在30秒內被讀完(以及理解),儘量將代碼行數控制在一頁或者一屏之內。
當考慮需要什麼類以及類要有什麼方法時,應該嘗試下面的方法。
(1)寫下問題的描述(程序要做什麼),把所有名詞、動詞、形容詞加下劃線
(2)對於所有名詞,用作可能的類。
(3)對於所有動詞,用作可能的方法。
(4)對於所有形容詞,用作可能的特性。
(5)把所有方法特性分配到類。
現在已經有了面向對象模型的草圖了,還可以考慮類和對象之間的關係(比如繼承或協作)
以及它們的作用,可以用以下步驟精煉模型。
(1)寫下(想象)一系列使用實列,也就是程序應用時的場景,試着包括所有的功能。
(2)一步步考慮每個使用實列,保證每個模型包括所有需要的東西,如果有遺漏的話就添加進來,
如果某處不太正確則改正。繼續,到滿意爲止。