首先:錯誤地使用了abc
模塊(see the docs)。您的班級A
應該具有abc.ABCMeta
作爲元類。所以如果你已經在使用元類,你可以將它擴展到你的優勢。
從abc.ABCMeta
繼承,使abstractmethod
工作和裝飾do_thing
薈萃類:
from abc import ABCMeta, abstractmethod
class DecoratingMeta(ABCMeta):
def __new__(cls, *args):
new_class = super(DecoratingMeta, cls).__new__(cls, *args)
# decorating do_thing manually
new_class.do_thing = new_class.do_thing_decorator(new_class.do_thing)
return new_class
現在您的抽象基類與默認勾選裝飾,什麼也不做:
# class Abstract(metaclass=ABCMeta): in python3
class Abstract(object):
__metaclass__ = DecoratingMeta # remove this line in python3
@abstractmethod
def do_thing(self, input):
pass
@classmethod
def do_thing_decorator(cls, function):
return function # default decorator that does nothing
注意do_thing_decorator
在這種情況下必須是類方法。 對於在python3
和python2
中工作的元類,請參閱six。
只實現特定的檢查,但仍然是抽象你檢查類:
class Checker(Abstract):
@classmethod
def do_thing_decorator(cls, function):
def do_checked_thing(self, input):
check = function(self, input) # NOT self.do_thing(input) else recursion error
if check != 1:
raise ValueError("Check failed")
return check
return do_checked_thing
注意,你寫check = do_thing_func(input)
線將導致遞歸錯誤。
和你有一個樣本實現的do_thing
具體類:
class Concrete(Checker):
def do_thing(self, input):
return input # sample implementation
您可以驗證do_thing(1)
成功和失敗do_thing(2)
c = Concrete()
c.do_thing(1)
try:
c.do_thing(2)
except ValueError:
print("check failed")
這種方法的缺點是,你不能讓抽象的do_thing_decorator
。
因此,這已經是一個大量的文字,但如果你不希望在所有使用任何元類有一個更簡單的方法:
寫,通過執行在do_thing
方法檢查一類使用兩個「抽象」的方法:
class Abstract(object):
def do_thing_func(self, input):
raise NotImplementedError()
def check_do_thing(self, result):
raise NotImplementedError()
# don't override this method
def do_thing(self, input):
result = self.do_thing_func(input)
self.check_do_thing(result) # may raise
return result # if it does not raise return the result
注意do_thing_func
和check_do_thing
是不是真的抽象的,你可以Abstract
類型仍然實例化對象。如果你需要它們抽象,在這裏使用標準的abc.ABCMeta
元類。
現在創建一個實現check_do_thing
class Checker(Abstract):
def check_do_thing(self, result):
if result != 1:
raise ValueError("check failed")
這變得更簡單,因爲我們不需要這裏裝飾一檢查類。
最後一個實現do_thing_func
class Concrete(Checker):
def do_thing_func(self, input):
return input # sample implementation
注意Concrete
現在必須實現do_thing_func
但是當你使用類,你必須調用do_thing
具體類。
這裏的缺點是,你仍然可以覆蓋do_thing
從而打破檢查。
你看過'__new __()'方法嗎? –
@ IgnacioVazquez-Abrams不是一個不合理的解決方案。我希望在方法層面有更直觀的一些,但如果我找不到更好的東西,可能會默認。 –