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' |