抽象基類
有些物件導向的語言,如JAVA,支援介面,可以聲明一個支援給定的一些方法方法,或者支援給定存取協議的類。抽象基類(或者ABCs)是Python裡一個相同的特性。抽象基類由abc模組構成,包含了一個叫做ABCMeta的metaclass。這個metaclass由內建的isinstance()和issubclass()特別處理,並包含一批會被Python開發人員廣泛用到的基礎抽象基類。將來的Python版本可能會加入更多的抽象基類。
比如說有某個特定類你想知道它是否支援dictionary類型的存取。然而dictionary類型是個模糊的表述。它可能意味著可以通過obj[1]進行存取。那是否也意味著obj[2]= value這種賦值也起作用呢?又或者該對象將具備keys(), values()和items()方法?迭代的變種如iterkeys(),copy()和update()又如何呢?通過對象迭代的iter()呢?
Python 2.6的collections模組包括了許多不同的抽象基類來表示出這些不同。Iterable表明一個類定義了__iter__(),Container意味著該類定義了__contains__()方法,因此支援x in y運算式。基本的dictionary介面包括存取資料和keys(),values(),以及items(),由MutableMapping抽象基類定義。
你可以讓你的類繼承某個特定的抽象基類,來表示它們支援抽象基類介面:
import collections
class Storage(collections.MutableMapping):
...
另外,你可以不繼承基類,以調用抽象基類的register()方法的方式註冊該類。
import collections
class Storage:
...
collections.MutableMapping.register(Storage)
相對於你寫的類來說,從抽象基類繼承可能更清晰。當你已經寫了一個新的抽象基類,能描述一個存在的類型或類,或者你想聲明某些第三方類實現了一個抽象基類,
register()方法是有用的。例如,如果你定義了一個PrintableType抽象基類,以下是合法的:
# Register Python's types
PrintableType.register(int)
PrintableType.register(float)
PrintableType.register(str)
類應當遵循由抽象基類指明的語義,但是Python不能檢查這一點;類作者應該理解抽象基類的需求,並據此實現代碼。
要檢查一個對象是否支援某個特定介面,你可以這樣寫:
def func(d):
if not isinstance(d, collections.MutableMapping):
raise ValueError("Mapping object expected, not %r" % d)
不要認為你必須像上面的例子那樣,寫許多檢查性的代碼。Python有很強的duck-typing傳統,從來不會進行顯式的類型檢查。代碼只是簡單的調用對象的方法,認為這些方
法會存在,如果不存在就會拋出異常。抽象基類檢查時一定要謹慎,最好在非常必要的時候才那樣做。
你可以在類的定義中用abc.ABCMeta作為metaclass寫自己的抽象基類:
from abc import ABCMeta, abstractmethod
class Drawable():
__metaclass__ = ABCMeta
@abstractmethod
def draw(self, x, y, scale=1.0):
pass
def draw_doubled(self, x, y):
self.draw(x, y, scale=2.0)
class Square(Drawable):
def draw(self, x, y, scale):
...
在以上的Drawable抽象基類中,draw_doubled()方法會按對象兩倍的大小畫出來,並且可以調用Drawable自己的方法來實現。因此實現這個抽象基類的類不需要
提供它們自己的draw_doubled()實現,儘管他們可以那樣做。然而draw()的實現是必須的;抽象基類不能提供一個有用的一般實現。
你可以在必須實現的方法,如draw()中應用@abstractmethod修飾符;Python會對那些沒有定義該方法的類拋出異常。注意,只有當你試圖建立一個子類執行個體,但是卻缺少該方法的時候才會拋出異常。
>>>class Circle(Drawable):
... pass
...
>>>c=Circle()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Circle with abstract methods draw
>>>
抽象資料屬性可以用@abstractproperty decorator聲明:
from abc import abstractproperty
...
@abstractproperty
def readonly(self):
return self._x
子類必須定義一個readonly()屬性。
===================================
http://bbs.chinaunix.net/thread-771123-1-1.html
java中的抽象類別是為了實現c++中的抽象類別和模板之類的東西
介面是為瞭解決java不能多繼承的問題
很顯然樓主是從java才開始接觸物件導向程式設計的。實際上java的“介面”是一個特例而非普通現象。如果可以多繼承的話,那還要介面幹什嗎?
實際上python才是最符合現實邏輯的“物件導向”
python允許多繼承,正如現實中,你既是公民也是納稅人,我們直接使用這些“類”而不需要特別的建立什麼“納稅人介面”
python中所有的類,都是抽象類別,或者說根本不存在抽象類別,類方法可以直接使用,“類”本身在定義的時候就已經執行個體化,你可以通過輸入:某類[斷行符號]看到其記憶體控制代碼。這是符合事實的,並且時簡約明了的。
而在C++和java當中,一個類定義了以後,肯定是佔用了記憶體空間,但是同時他又沒有執行個體化,如果要使用的話還得執行個體化一次,又要佔用一些記憶體空間。而類定義所佔用的記憶體空間,使用率很低。
python中不存在“基類”的概念,也沒有單根,更沒有基本類型,所有的一切都是對象。
python是無神論的最完美體現,沒有亞當,沒有上帝,沒有鬼神,沒有唯一的主。你愛信什麼信什麼,愛是什麼是什麼,沒有任何約束,但是不能存在特殊。
另外,python根本沒有意去模仿java的介面,因為那完全沒必要,python的標準類就完全包含java中的介面的所有功能。倒是模仿一下c++的模板會有些實際用途。
====================================
python介面的例子
http://pypi.python.org/pypi/zope.interface
twisted的twisted\internet\interface.py裡使用zope.interface