python的介面和抽象類別

來源:互聯網
上載者:User

抽象基類

有些物件導向的語言,如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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.