熱線電話:13121318867

登錄
首頁精彩閱讀在Python中定義和使用抽象類的方法
在Python中定義和使用抽象類的方法
2017-11-14
收藏

在Python中定義和使用抽象類的方法

提起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__      # {'say': <function say at 0x7f...>, ...}
print A.__subclasshook__(B) # True

不完整的實現    
class D(A):
  def save(self, output, data):
    return output.write(data)
 
if __name__ == '__main__':
  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 'base class reading data'
    return input.read()
 
 
class B(A):
 
  def retrieve_values(self, input):
    base_data = super(B, self).retrieve_values(input)
    print 'subclass sorting data'
    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
['line one', 'line two', 'line three']

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

抽象屬性    
import abc
 
class A(object):
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractproperty
  def value(self):
    return 'should never get here.'
 
class B(A):
   
  @property
  def value(self):
    return 'concrete property.'
 
try:
  a = A()
  print 'A.value', a.value
except Exception, err:
  print 'Error: ', str(err)
 
b = B()
print 'B.value', b.value

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

定義抽象的讀寫屬性    
import abc
 
class A(object):
  __metaclass__ = abc.ABCMeta
 
  def value_getter(self):
    return 'Should never see this.'
 
  def value_setter(self, value):
    return
 
  value = abc.abstractproperty(value_getter, value_setter)
 
class B(A):
   
  @abc.abstractproperty
  def value(self):
    return 'read-only'
 
class C(A):
  _value = 'default value'
 
  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 = 'hello'
print c.value

打印結果, 定義具體類的property時必須與抽象的abstract property相同。如果只覆蓋其中一個將不會工作.    
error: ...
error: ...
print 'default value'
print 'hello'

使用裝飾器語法來實現讀寫的抽象屬性, 讀和寫的方法應該相同.    
import abc
 
class A(object):
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractproperty
  def value(self):
    return 'should never see this.'
 
  @value.setter
  def value(self, _value):
    return
 
class B(A):
  _value = 'default'
 
  @property
  def value(self):
    return self._value
 
  @value.setter
  def value(self, _value):
    self._value = _value
 
b = B()
print b.value    # print 'default'
 
b.value = 'hello'
print b.value    # print 'hello'


數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢