在Python中,一切皆為對象,所有的對象都有一些相同的內容,在PyObject中定義。
//xk> 怎樣實現繼承
PyObject是Python中一切(new style)類的基類,其定義非常簡單
//xk> Python3.2.2_Source/Include/Object.h
typedef struct _object {
_PyObejct_HEAD_EXTRA
Py_ssize_t ob_refcnt; //xk> reference count
struct _typeobject *ob_type; //xk> object的類型用type object來表示
} PyObject; |
_PyObejct_HEAD_EXTRA宏不用管,在發布版Python中沒有編譯。PyObject結構體中僅僅定義了引用計數和類型資訊。對象的類型也是對象(typedef _typeobject{...}PyTypeObject;),用類型對象來表示類型資訊。
怎麼用C語言實現繼承關係呢?子類繼承了父類的內容,並有所增改,所以在記憶體布局上,只要把父類的內容放在對象的頭部,就可以用父類指標指向子類對象。在Python內部,每個對象都有相同的對象頭部——PyObejct的內容,這就使得在Python內部,對對象的引用變得非常統一,只需要用一個PyObject *指標就可以引用任意的對象。這對於實現多態是必要的。
//xk> 怎樣表示類型
對象的類型定義了對象的資料成員和能夠施加在對象之上的操作。查看Python3.2.2_Source/Include/Object.h中對_typeobejct的定義(內容非常多,不能在這裡全部帖出來),包含了大量的函數指標。這些函數指標即表示該類型所定義的操作,亦即表示該類型的對象在運行時所表現的行為。
在這些操作資訊中,有三個指標比較重要:tp_as_number, tp_as_sequence, tp_as_mapping。以tp_as_number為例,它是PyNumberMethonds *指標,而PyNumberMethonds結構體定義了作為一個數值對象應該支援的操作。類似的,tp_as_sequence表示作為一個序列對象所支援的操作;tp_as_mapping表示作為一個關聯對象所支援的操作。可見:在Python中,一個對象可以同時是數值對象、序列對象、關聯對象,關鍵看它支援哪些操作,也就是定義了哪些非NULL的函數指標。因此,Python對象的多態性是基於行為的,而不像C++/Java等語言中多態性是基於類型的。Python對象實際上是全類型的,可以有的函數指標全部都有,只不過很多函數指標都是NULL,只要你實現了該函數,python對象就能表現出該行為。
>>> class MyInt(int):
def __getitem__(self, key):
return key + str(self)
>>> a = MyInt(1)
>>> b = MyInt(2)
>>> print a + b
3
>>> a['key']
'key1' |
定義了一個子類從內建的int類繼承而來,應該是數值對象,但是因為通過定義__getitem__方法,將MyInt在Python內部對應的PyTypeObejct對象中原本為NULL的函數指標重新賦值,使得該類型的對象能夠表現出關聯對象的特性。
//xk> Python對象的多態性
通過PyObject和PyTypeObejct,Python利用C語言實現了類似C++所提供的對象多態性(但是有所不同)。在Python中建立一個對象比如PyIntObject對象時,Python內部是用PyObject *指標而不是PyIntObject *指標來儲存和維護這個對象,在Python內部各個函數之間傳遞的都是一種泛型指標——PyObject *,因此無法根據指標類型判斷所指的對象究竟是個什麼類型,只能從指標所指對象的ob_type域動態地進行判斷。由此,Python實現了多態機制。
//xk> 亂彈:C哲學和C++哲學的比較
C哲學:保持簡單。
C++哲學:用複雜的工具對付複雜的現實問題,以此擷取解決方案的簡單直接。
C和C++都意識到程式設計的本質問題是控制複雜度,只不過它們採用了不同的思路。
C語言選擇用分治法,模組化將一個複雜問題分解成許多相對簡單的小問題,並精心設計模組之間的通訊。這裡的模組可以是一個函數、一個進程甚至一個獨立的程式。Unix工具鏈哲學與此一脈相承。
《C++沉思錄》中闡明:類似汽車製造等傳統工業,一方面使用者介面越來越簡單,另一方面內部實現越來越複雜。我們生活在一個如此複雜的世界裡,因此Java和C#也不可避免地變得越來越複雜。C++的複雜源於要解決的現實問題的複雜。
從理論上爭論孰優孰劣是毫無意義的,兩者都很有道理。C語言的選擇有一定的問題,從整體來看模組化的設計容易導致多餘(Python的每個對象都要定義對所有類型的操作的支援,大量的函數指標被設定為NULL),用C來實現物件導向的機制明顯不如C++簡單直接。雖然如此,C語言貌似要比C++受到更廣泛的支援。C++貌似真的過於複雜了,既難於學習,開發效率又低。在面對非常非常複雜的問題時,從整體上來把握對操刀者提出了很高的要求,分而治之雖然難免冗餘,好歹能夠可行。
最後說一句,對學生來說,選擇哪個都沒有錯,餓死於乾草堆之間才是最大的愚蠢。學習盡量與手頭上的項目結合,把手上看似平淡無奇的事情做得比別人深入一步,learn by doing it.