Python實現抽象基類的3三種方法__Python

來源:互聯網
上載者:User

Python的抽象基類類似於Java、C++等物件導向語言中的介面的概念。抽象基類提供了一種要求子類實現指定協議的方式,如果一個抽象基類要求實現指定的方法,而子類沒有實現的話,當試圖建立子類或者執行子類代碼時會拋出異常。這裡簡單介紹一下Python實現抽象基類的三種方法。


方法一:使用NotImplementedError

見下面的測試代碼,只有子類實現了run方法才能運行run。

>>> class Task():    def __init__(self, x, y):        self.x = x        self.y = y>>> class Task():    def __init__(self, x, y):        self.x = x        self.y = y    def run(self):        raise NotImplementedError('Please define "a run method"')>>> t = Task(1, 2)>>> t.run()Traceback (most recent call last):  File "<pyshell#12>", line 1, in <module>    t.run()  File "<pyshell#10>", line 6, in run    raise NotImplementedError('Please define "a run method"')NotImplementedError: Please define "a run method">>>>>> class SubTask(Task):    def __init__(self, x, y):        super().__init__(x, y)    def run(self):        print('Task(x=%s, y=%s)' % (self.x, self.y))>>> st = SubTask(1, 3)>>> st.run()Task(x=1, y=3)>>> 


方法二:使用元類

class TaskMeta(type):    def __new__(cls, name, bases, attrs):        new_class = super(TaskMeta, cls).__new__(cls, name, bases, attrs)        if attrs.pop('abstract', False):            return new_class        if not hasattr(new_class, 'run') or not callable(new_class.run):            raise TypeError('Please define "a run method"')        return new_classclass Task(metaclass=TaskMeta):    abstract = True    def __init__(self, x, y):        self.x = x        self.y = yclass SubTask(Task):    def __init__(self, x, y):        super().__init__(x, y)    def run(self):        print('Task(x=%s, y=%s)' % (self.x, self.y))

測試代碼一:

 
 
>>> t = Task(1, 3)>>> t.run()Traceback (most recent call last):  File "E:/Code/python3/loggingTest/task.py", line 32, in <module>    t.run()AttributeError: 'Task' object has no attribute 'run'>>> st = SubTask(1, 3)>>> st.run()Task(x=1, y=3)


這個樣本類似於方法一,但有一些細微的區別。第一個區別就是Task類本身仍然能被執行個體化,但是不能運行run方法,否則會拋出AttributeError錯誤。更為重要的區別在於子類。當子類被建立時元類會運行__new__方法,解譯器講不再允許建立沒有run方法的子類。

>>> class SubTask(Task):...    pass...Traceback (most recent call last):  File "E:/Code/python3/loggingTest/task.py", line 31, in <module>    class SubTask(Task):  File "E:/Code/python3/loggingTest/task.py", line 10, in __new__    raise TypeError('Please define "a run method"')TypeError: Please define "a run method"


方法三:使用@abstractmethod

  abc模組提供了一個使用某個抽象基類聲明協議的機制,並且子類一定要提供了一個符合該協議的實現。

import abcclass Task(metaclass = abc.ABCMeta):    def __init__(self, x, y):        self.x = x        self.y = y    @abc.abstractmethod    def run(self):        passclass SubTask(Task):    def __init(self, x, y):        super().__init__(x, y)    def run(self):        print('Task(x=%s, y=%s)' % (self.x, self.y))class OtherSubTask(Task):    def __init(self, x, y):        super().__init__(x, y)

和方法一、方法二的樣本類似,但略有不同。第一,Task類本身不能被執行個體化。

>>> t = Task(1, 3)Traceback (most recent call last):  File "E:/Code/python3/loggingTest/test.py", line 23, in <module>    t = Task(1, 3)TypeError: Can't instantiate abstract class Task with abstract methods run


這與方法一不同,方法一允許基類Task被執行個體化。

對於不能正確重寫run方法的子類,在錯誤的情況下它與之前的兩個方法的差別也是不同的。方法一中,使用NotImplementedError,最終在run方法被調用時引發NotImplementedError錯誤。在方法二中,使用了自訂的TaskMeta元類, 當這個抽象類別被建立時引發TypeError錯誤。

當沒有實現run方法的子類執行個體化時會報錯,給出的錯誤資訊與執行個體化Task類時給出的一樣,邏輯上完全符合預期。

>>> ot = OtherSubTask(1, 3)Traceback (most recent call last):  File "E:/Code/python3/loggingTest/test.py", line 27, in <module>    ot = OtherSubTask(1, 3)TypeError: Can't instantiate abstract class OtherSubTask with abstract methods run
但是,當你定義了一個重新了run方法的子類時,那麼子類就能夠被執行個體化,就能正常工作。

>>> st = SubTask(1, 3)>>> st.run()Task(x=1, y=3)



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.