轉載請註明出處http://blog.csdn.net/liygcheng/article/details/22905439
我們先來看一個簡單的例子:
#author liygcheng 2014-04-04#object-oriented python class Animal():def __init__(self):self.__name = "Animal"print(self.__name)def accessMethod(self):print("I am a animal,and my name is:")print(self.__name)print("\n The Additional message is:")self.__innerAccess()def __innerAcess():print("this can not be seen!")@staticmethoddef staticMethod():print("this is a static method!")@property #python中的屬性設定def name(self):return self.__name@name.setterdef name(self, value):self.__name = value@name.deleterdef name(self):del self.__name
例子中的其他問題暫且先不考慮,因為我在編譯的時候,出了問題,總是會出現“IndentationError: unindent does not match any outer indentationlevel”這樣的錯誤,在網上一查之後發現原來是混用了Tab鍵和空格。。下面我們開始看看代碼中出現的一些知識點:
私人函數和靜態方法在之前的類介紹中詳細闡述過,此不再贅述,這裡我們把重點放在這個@property這裡,
在C++或者Java中,我們經常會遇到setter和getter,在這裡@property的作用類似,需要注意的是,這裡面的同一屬性的三個函數要同名(本例中指的是name),當我們在運用的時候,就可以根據需要,例如是否唯讀等進行設定。其實除此之外,在python2.6之前,還有一種綁定的方法,先來看一個例子:
那麼另一種綁定的方法是什麼呢?我們來看一下:
可以發現,這兩種效果是一樣的,但是在python中,我們推薦使用前者。
2.繼承
關於繼承,可能更多的,我們可能是在C++,Java中第一次見到,但是物件導向的思想是不變的,在python中也一樣,可能我們經常會在各種專業書籍上發現is-a和has-a,繼承關係就是典型的is-a(組合是has-a).在繼承中,我們要注意一些事情:
1. 在能用組合解決問題的時候,優先考慮組合
2. 繼承者基類的構造方法不會自動調用,需要在子類的構造方法中明確調用
3. Python總是沿著繼承樹從底至上進行搜尋
來看一個簡單的例子:
注意:當用subline Text 啟動並執行時候出現”Decodeerror-output not utf-8”這個錯誤的時候,是因為中文的原因,直接在Subline Text 的python外掛程式中修改檔案即可,具體操作如下:
1. 找到Python.sublime-build檔案,具體位置如我的在:
C:\Users\liygcheng\AppData\Roaming\Sublime Text 2\Packages\Python
2. 在該檔案最後加上一欄“encoding”:”cp936”,如下,別忘了上一欄最末的逗號
1. 至於cp936是什麼,維基百科的解釋是這樣的:
微軟的CP936通常被視為等同GBK,連 IANA 也以“CP936”為“GBK”之別名[1]。事實上比較起來, GBK 定義之字元較 CP936 多出95字(15個非漢字及80個漢字)
幾個值得思考的問題:
1. 當我們在python中想要調用父類的某個方法的時候,如果總是使用非綁定的類方法,即通過類名引用,並在參數列表中,引入的這個待綁定的對象的時候,如果一個子類的父類發生了變化,必須把所有的父類全部更換,軟體工程的直覺告訴我們,這樣是不可取的,因為程式員總是偷懶的,稍微查了一下,發現python自從2.2開始之後添加了一個關鍵字super,來解決這個問題:
官方給出的說明是這樣的:
super(type[, object-or-type])
Return the superclass of type. If the second argumentis omitted the super object
returned is unbound. If the second argument is an object,isinstance(obj, type)
must be true. If the second argument is a type, issubclass(type2,type) must be
true. super() only works for new-style classes.
A typical use for calling a cooperative superclassmethod is:
class C(B):
def meth(self, arg):
super(C,self).meth(arg)
New in version 2.2.
簡而言之,我們可以這麼理解super(type,arg).method(..),當執行這條語句的時候,首先找到類type的父類,然後將類type或其子類的對象arg提升為類type的父類類型對象,然後調用類type的父類方法method.來看一個例子:
2 多重繼承的問題
我們知道,在Java中不存在多重繼承,直接改用介面,在C++中,我們引入了虛基類,那麼在python中是否會有這個問題呢?
我們先來看一個例子:
在這個例子中,我們發現,單獨使用super或者單獨使用非綁定的函數都會正確初始化,但是當我們混用了super與非綁定的方法,發現存在父類被調用多次的現象,因此需要注意。
下面來分析一下多重繼承的繼承樹結構,簡單概括繼承樹如(省去根Object):
我們根據之前的結果得知,類F初始化的路徑為:F-> C -> D -> A,咋一看,我們估計只能判斷這是從底紙上的初始化,至於具體使用了何種演算法還不得而知,po主查了一下資料,發現python多重繼承在2.3之前是基於深搜演算法的,但是在之後採用的是C3演算法搜尋繼承樹,
(Mro, 即Method resolution order 主要用於在多重繼承時判斷調用屬性路徑),至於為什麼要用C3演算法,主要是考慮到繼承時聲明的父類順序,可以這麼簡單的理解,C3演算法就是要先確定一個線性序列,如下:
1. 如果是繼承1個基類
class B(A)
這個時候的mro序列即為mro(B) = [B,A]
2. 如果繼承至多個基類
class B(A1,A2,A3,….)
這時mro序列為
mro(B) =
[B] + merge(mro(A1),mro(A2),….,[A1,A2,A3,……])
可以這麼說,這麼的合并merge操作是整個C3演算法的核心,遍曆執行merge操作的序列,如果一個序列的第一個元素,在其他序列中也是第一個元素,或不在其他序列出現,則從所有執行merge操作序列中刪除這個元素,合并到當前的mro中。merge操作後的序列,繼續執行merge操作,直到merge操作的序列為空白。如果merge操作的序列無法為空白,則說明不合法。
對之前的例子,我們來分析一下繼承樹://0標誌基類object
mro(A) =[A,0]
mro(B) =[B,0]
mro(C) = [C]+ mro(A) = [C] + [A,0] = [C,A,0]
mro(D) =[D] + mro(A) = [D] + [A,0] = [D,A,0]
mro(E) = [E] +merge(mro(B) ,mro(C),[B,C])
= [E] + merge([C,A,0],[B,0],[B,C])
=[E,B] + merge([C,A,0],[0],[C])
=[E,B,C] + merge([A,0],[0])
=[E,B,C,A] + merge([0])
=[E,B,C,A,0]
Mro(F) = [F] + merge(mro(C),mro(D),[C,D])
=[F] +merge([C,A,0],[D,A,0],[C,D])
=[F,C] + merge([A,0],[D,A,0],[D])
=[F,C,D] +merge([A,0],[A,0])
=[F,C,D,A] +merge([0],[0])
=[F,C,D,A,0]
這下總明白為什麼類F初始化的順序是F-> C -> D -> A 了吧