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

https://www.jb51.net/article/87710.htmjava

 

像java同樣python也能夠定義一個抽象類。python

在講抽象類以前,先說下抽象方法的實現。ssh

抽象方法是基類中定義的方法,但卻沒有任何實現。在java中,能夠把方法申明成一個接口。而在python中實現一個抽象方法的簡單的方法是:this

?
1
2
3
class Sheep( object ):
   def get_size( self ):
     raise NotImplementedError

任何從Sheep繼承下來的子類必須實現get_size方法。不然就會產生一個錯誤。但這種實現方法有個缺點。定義的子類只有調用那個方法時纔會拋錯。這裏有個簡單方法能夠在類被實例化後觸發它。使用python提供的abc模塊。spa

?
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)時候都會拋出異常。.net

所以,經過定義抽象類,能夠定義子類的共同method(強制其實現)。code

如何使用抽象類htm

?
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'
相關文章
相關標籤/搜索