Python面向對象特征總結


抽象是隱藏多余細節的藝術。在面向對象的概念中,抽象的直接表現形式通常為類。Python基本上提供了面向對象編程語言的所有元素,如果你已經至少掌握了一門面向對象語言,那么利用Python進行面向對象程序設計將會相當容易。

一、封裝

面向對象程序設計中的術語對象(Object)基本上可以看做數據(特性)以及由一系列可以存取、操作這些數據的方法所組成的集合。傳統意義上的“程序=數據結構+算法”被封裝”掩蓋“並簡化為“程序=對象+消息”。對象是類的實例,類的抽象則需要經過封裝。封裝可以讓調用者不用關心對象是如何構建的而直接進行使用。

一個簡單的Python類封裝如下:

Encapsulation

 

上面簡單的示例代碼可以看出,Python中的類包含了一般面向對象編程語言的主要元素,比如構造方法、綁定方法、靜態方法、屬性等,如果深入下去,還可以發現Python中內置了很多面向對象的“高級”主題,比如迭代器反射特性等等,提供了封裝的直接構造要素。

 

二、繼承

1、類繼承

繼承給人的直接感覺是這是一種復用代碼的行為。繼承可以理解為它是以普通的類為基礎建立專門的類對象,子類和它繼承的父類是IS-A的關系。一個簡單而不失經典的示例如下:

Inheritance

 

一個顯而易見的特點是,Python的面向對象的繼承特征是基於類(class)的,比javascript基於原型(prototype)的繼承更容易組織和編寫代碼,也更容易讓人接受和理解。

ps:最近幾天Anders大神搞出來的TypeScript橫空出世,看它的語言規范里繼承也是基於類的:

TypeScript-SimpleInheritance

 

感覺基於類的繼承的語言好像在實現OO的可讀性和編程體驗上都不太差,據傳說javascript是碼農最想噴也是噴過最多f**k的語言。

2、多重繼承

不同於C#,Python是支持多重類繼承的(C#可繼承自多個Interface,但最多繼承自一個類)。多重繼承機制有時很好用,但是它容易讓事情變得復雜。一個多重繼承的示例如下:

MultInheritance

 

如你所看到的那樣,多重繼承的好處顯而易見,我們可以輕而易舉地通過類似“組合”的方式復用代碼構造一個類型。

有個需要注意的地方,即如果一個方法從多個超類繼承,那么務必要小心繼承的超類(或者基類)的順序:

MultInheritance

 

我們為動物和機器各實現一個相同名稱的move方法,但是輸出因為繼承的順序而有所不同,Python在查找給定方法或者特性時訪問超類的順序被稱為MRO(Method Resolution Order,方法判定順序)。

三、多態

多態意味着可以對不同的對象使用同樣的操作,但它們可能會以多種形態呈現出結果。在Python中,任何不知道對象到底是什么類型,但又需要對象做點什么的時候,都會用到多態。

能夠直接說明多態的兩段示例代碼如下:

1、方法多態

Method-Polymorphism

 

對於一個臨時對象obj,它通過Python的隨機函數取出來,不知道具體類型(是字符串、元組還是自定義類型),都可以調用count方法進行計算,至於count由誰(哪種類型)去做怎么去實現我們並不關心。

有一種稱為”鴨子類型(duck typing)“的東西,講的也是多態:

DuckTyping

就in_the_forest函數而言,參數對象是一個鴨子類型,它實現了方法多態。但是實際上我們知道,從嚴格的抽象來講,Person類型和Duck完全風馬牛不相及。

2、運算符也多態

Operator-Polymorphism

 

上例中,顯而易見,Python的加法運算符是”多態“的,理論上,我們實現的add方法支持任意支持加法的對象,但是我們不用關心兩個參數x和y具體是什么類型。

一兩個示例代碼當然不能從根本上說明多態。普遍認為面向對象最有價值最被低估的特征其實是多態。我們所理解的多態的實現和子類的虛函數地址綁定有關系,多態的效果其實和函數地址運行時動態綁定有關。在C#中實現多態的方式通常有重寫重載兩種,從上面兩段代碼,我們其實可以分析得出Python中實現多態也可以變相理解為重寫和重載。在Python中很多內置函數和運算符都是多態的。

號外:在C#中,我們熟知接口(Interface)和多態相關,在處理多態對象時,只要關心它的接口(或者稱為“協議”)而不需要顯式指定特定實現類型即可,這也是IoC中面向接口(抽象)而不依賴於具體實現編程的基礎。可惜在Python中根本沒有Interface(有抽象類)。而在TypeScript的Specification中引入了Interface的概念:

TypeScript-Interface

 

TypeScript語言規范里對Interface的定義是命名的對象類型(Programmers can give names to object types; we call named object types interfaces. )。它直接等價於下面的Ojbect Type:

var Friend: () => {
    name: string; favoriteColor?: string;
};

上面這個Object Type在Playgound中等價的javascript代碼如下:

var Friend;

在TypeScript編程規范文檔里,對Interface的一些說明:

Interfaces provide the ability to give names to object types and the ability to compose existing named object types into new ones.
Interfaces have no run-time representation—they are purely a compile-time construct. Interfaces are particularly useful for documenting and validating the required shape of properties, objects passed as parameters, and objects returned from functions
.

Interface可以繼承自Interface:

TypeScript-InterfaceInheritInterface

 

我們嘗試讓類繼承自Interface:

TypeScript-ClassInheritInterface

 

實踐證明類是不能繼承實現Interface的:A export class may only extend other classes, Mover is an interface.

現在大家知道TypeScript里的Interface和我們所認識和理解的接口的區別了嗎?相同的一個名詞Interface,不同語境下意義並不完全相同,看上去好像是挺傻的,但是學習和使用語言不做對比幾乎是不可能的。

 

參考:

http://www.python.org/

http://zh.wikipedia.org/wiki/Duck_typing

http://typescript.codeplex.com/

http://www.typescriptlang.org/Playground/

http://www.nczonline.net/blog/2012/10/04/thoughts-on-typescript/


免責聲明!

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



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