首頁  >  文章  >  後端開發  >  Python中定義並使用抽象類

Python中定義並使用抽象類

高洛峰
高洛峰原創
2017-03-01 13:49:161408瀏覽

提起Java的抽象類別大家都比較熟悉,Python中我們可以使用abc模組來建構抽象類別,這裡就為大家講解在Python中定義和使用抽象類別的方法

像java一樣python也可以定義一個抽象類別。

在講抽象類別之前,先說下抽象方法的實作。

抽象方法是基底類別中定義的方法,但卻沒有任何實作。在java中,可以把方法申明成一個介面。而在python中實作一個抽象方法的簡單的方法是:

class Sheep(object):
  def get_size(self):
    raise NotImplementedError

任何從Sheep繼承下來的子類別必須實作get_size方法。否則就會產生一個錯誤。但這種實作方法有個缺點。定義的子類別只有在呼叫那個方法時才會拋錯。這裡有個簡單方法可以在類別被實例化後觸發它。使用python提供的abc模組。

import abc
class Sheep(object):
  __metaclass__ = abc.ABCMeta
  
  @abc.absractmethod
  def get_size(self):
    return


這裡實例化Sheep類別或任意從其繼承的子類別(未實作get_size)時候都會拋出例外。

因此,透過定義抽象類,可以定義子類別的共同method(強制其實現)。

如何使用抽象類別

import abc 

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def load(self, input):
    return 

  @abc.abstractmethod
  def save(self, output, data):
    return

#透過ABCMeta元素類別來建立一個抽象類別, 使用abstractmethod裝飾器來表明抽象方法

註冊具體類別

class B(object):
  
  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)

A.register(B)

if __name__ == '__main__':
  print issubclass(B, A)   # print True
  print isinstance(B(), A)  # print True

從抽象類別註冊一個具體的類別

子類別化實作

class C(A):

  def load(self, input):
    return input.read()

  def save(self, output, data):
    return output.write(data)
    
if __name__ == '__main__':
  print issubclass(C, A)   # print True
  print isinstance(C(), A)  # print True

#可以使用繼承抽象類別的方法來實作具體類別這樣可以避免使用register. 但是副作用是可以透過基底類別找出所有的具體類別

for sc in A.__subclasses__():
  print sc.__name__

# print C

如果使用繼承的方式會找出所有的具體類,如果使用register的方式則不會被找出

使用__subclasshook__

使用__subclasshook__後只要具體類別定義了與抽象類別相同的方法就認為是他的子類別

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def say(self):
    return 'say yeah'

  @classmethod
  def __subclasshook__(cls, C):
    if cls is A:
      if any("say" in B.__dict__ for B in C.__mro__):
        return True
    return NotTmplementd

class B(object):
  def say(self):
    return 'hello'

print issubclass(B, A)   # True
print isinstance(B(), A)  # True
print B.__dict__      # {&#39;say&#39;: <function say at 0x7f...>, ...}
print A.__subclasshook__(B) # True

不完整的實作

class D(A):
  def save(self, output, data):
    return output.write(data)

if __name__ == &#39;__main__&#39;:
  print issubclass(D, A)   # print True
  print isinstance(D(), A)  # raise TypeError

如果建置不完整的具體類別會拋出D不能實例化抽象類別和抽象方法

特定類別中使用抽象基底類別

#
import abc 
from cStringIO import StringIO

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def retrieve_values(self, input):
    pirnt &#39;base class reading data&#39;
    return input.read()


class B(A):

  def retrieve_values(self, input):
    base_data = super(B, self).retrieve_values(input)
    print &#39;subclass sorting data&#39;
    response = sorted(base_data.splitlines())
    return response

input = StringIO("""line one
line two
line three
""")

reader = B()
print reader.retrieve_values(input)

列印結果

base class reading data
subclass sorting data
[&#39;line one&#39;, &#39;line two&#39;, &#39;line three&#39;]

可以使用super來重複使用抽象基底類別中的羅輯, 但會迫使子類別提供覆寫方法.

抽象屬性

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return &#39;should never get here.&#39;

class B(A):
  
  @property
  def value(self):
    return &#39;concrete property.&#39;

try:
  a = A()
  print &#39;A.value&#39;, a.value
except Exception, err:
  print &#39;Error: &#39;, str(err)

b = B()
print &#39;B.value&#39;, b.value

列印結果,A不能被實例化,因為只有一個抽象的property getter method.

Error: ...
print concrete property

定義抽象的讀寫屬性

#
import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  def value_getter(self):
    return &#39;Should never see this.&#39;

  def value_setter(self, value):
    return 

  value = abc.abstractproperty(value_getter, value_setter)

class B(A):
  
  @abc.abstractproperty
  def value(self):
    return &#39;read-only&#39;

class C(A):
  _value = &#39;default value&#39;

  def value_getter(self):
    return self._value

  def value_setter(self, value):
    self._value = value

  value = property(value_getter, value_setter)

try:
  a = A()
  print a.value
except Exception, err:
  print str(err)

try:
  b = B()
  print b.value
except Exception, err:
  print str(err)

c = C()
print c.value

c.value = &#39;hello&#39;
print c.value

列印結果, 定義具體類別的property時必須與抽象的abstract property相同。如果只覆寫其中一個將不會工作.

error: ...
error: ...
print &#39;default value&#39;
print &#39;hello&#39;

使用裝飾器語法來實現讀寫的抽象屬性, 讀和寫的方法應該相同.

import abc

class A(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractproperty
  def value(self):
    return &#39;should never see this.&#39;

  @value.setter
  def value(self, _value):
    return 

class B(A):
  _value = &#39;default&#39;

  @property
  def value(self):
    return self._value

  @value.setter
  def value(self, _value):
    self._value = _value

b = B()
print b.value    # print &#39;default&#39;

b.value = &#39;hello&#39;
print b.value    # print &#39;hello&#39;


更多Python中定義和使用抽象類別相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn