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