在Python中定义和使用抽象类的方法
https://www.jb51.net/article/87710.htm
?
像java一樣python也可以定義一個抽象類。
在講抽象類之前,先說下抽象方法的實現。
抽象方法是基類中定義的方法,但卻沒有任何實現。在java中,可以把方法申明成一個接口。而在python中實現一個抽象方法的簡單的方法是:
?| 1 2 3 | class Sheep(object): ??def get_size(self): ????raise NotImplementedError |
任何從Sheep繼承下來的子類必須實現get_size方法。否則就會產生一個錯誤。但這種實現方法有個缺點。定義的子類只有調用那個方法時才會拋錯。這里有個簡單方法可以在類被實例化后觸發它。使用python提供的abc模塊。
?| 1 2 3 4 5 6 7 | import abc class Sheep(object): ??__metaclass__ = abc.ABCMeta ??? ??@abc.absractmethod ??def get_size(self): ????return |
這里實例化Sheep類或任意從其繼承的子類(未實現get_size)時候都會拋出異常。
因此,通過定義抽象類,可以定義子類的共同method(強制其實現)。
如何使用抽象類
?| 1 2 3 4 5 6 7 8 9 10 11 12 | 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裝飾器來表明抽象方法
注冊具體類
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
從抽象類注冊一個具體的類
子類化實現
?| 1 2 3 4 5 6 7 8 9 10 11 | 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. 但是副作用是可以通過基類找出所有的具體類
?| 1 2 3 4 | for sc in A.__subclasses__(): ??print sc.__name__ # print C |
如果使用繼承的方式會找出所有的具體類,如果使用register的方式則不會被找出
使用__subclasshook__
使用__subclasshook__后只要具體類定義了與抽象類相同的方法就認為是他的子類
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 |
不完整的實現
?| 1 2 3 4 5 6 7 | 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不能實例化抽象類和抽象方法
具體類中使用抽象基類
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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) |
打印結果
?| 1 2 3 | base class reading data subclass sorting data ['line one', 'line two', 'line three'] |
可以使用super來重用抽象基類中的羅輯, 但會迫使子類提供覆蓋方法.
抽象屬性
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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.
?| 1 2 | Error: ... print concrete property |
定義抽象的讀寫屬性
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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相同。如果只覆蓋其中一個將不會工作.
?| 1 2 3 4 | error: ... error: ... print 'default value' print 'hello' |
使用裝飾器語法來實現讀寫的抽象屬性, 讀和寫的方法應該相同.
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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' |
總結
以上是生活随笔為你收集整理的在Python中定义和使用抽象类的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS12
- 下一篇: 51CTO会员开通成功!开森!