像java一樣python也可以定義一個抽象類。
在講抽象類之前,先說下抽象方法的實現。
抽象方法是基類中定義的方法,但卻沒有任何實現。在java中,可以把方法申明成一個接口。而在python中實現一個抽象方法的簡單的方法是:
class Sheep(object): def get_size(self): raise NotImplementedError
任何從Sheep繼承下來的子類必須實現get_size方法。否則就會產生一個錯誤。但這種實現方法有個缺點。定義的子類只有調用那個方法時才會拋錯。這里有個簡單方法可以在類被實例化后觸發(fā)它。使用python提供的abc模塊。
import abcclass 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元類來創(chuàng)建一個抽象類, 使用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 abcclass 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 NotTmplementdclass B(object): def say(self): return 'hello'print issubclass(B, A) # Trueprint isinstance(B(), A) # Trueprint 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 StringIOclass 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 responseinput = StringIO("""line oneline twoline three""")reader = B()print reader.retrieve_values(input)打印結果
base class reading datasubclass sorting data['line one', 'line two', 'line three']
可以使用super來重用抽象基類中的羅輯, 但會迫使子類提供覆蓋方法.
抽象屬性
import abcclass 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.valueexcept Exception, err: print 'Error: ', str(err)b = B()print 'B.value', b.value
打印結果,A不能被實例化,因為只有一個抽象的property getter method.
Error: ...print concrete property
定義抽象的讀寫屬性
import abcclass 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.valueexcept Exception, err: print str(err)try: b = B() print b.valueexcept Exception, err: print str(err)c = C()print c.valuec.value = 'hello'print c.value
打印結果, 定義具體類的property時必須與抽象的abstract property相同。如果只覆蓋其中一個將不會工作.
error: ...error: ...print 'default value'print 'hello'
使用裝飾器語法來實現讀寫的抽象屬性, 讀和寫的方法應該相同.
import abcclass 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 = _valueb = B()print b.value # print 'default'b.value = 'hello'print b.value # print 'hello'
新聞熱點
疑難解答
圖片精選