首先:错误地使用了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不是一个不合理的解决方案。我希望在方法层面有更直观的一些,但如果我找不到更好的东西,可能会默认。 –