我认为这是一个相当简单的问题,但未能找到令人满意的答案。简而言之,我想在父类的子类上强制执行合同而不向每个子类添加逻辑。代码示例如下:
class A(object):
@abc.abstractmethod
def do_thing(self, input):
raise NotImplementedError
class A1(A):
def do_thing_decorator(self, do_thing_func):
def checked_do_thing(input):
check = do_thing_func(input)
if check != 1:
raise ValueError
return check
return checked_do_thing
所以问题是如何自动修饰继承自do_thing
的类实现的A1
函数?假设有一个A2
类,但检查稍有不同。
我的初步调查表明,元类是采取的方法,但很难找到有关它们如何工作的重要解释。理想情况下寻找在python 2.x中运行的东西,但如果只有3.x解决方案,我很乐意改变我的代码库。
答案 0 :(得分:2)
首先:您错误地使用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。
您的Checker类仅实现特定的检查程序,但仍然是抽象的:
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
摘要。
所以这已经是很多文字了,但是如果你根本不想使用任何元类,那么有一个更简单的方法:
使用两个" abstract"编写一个在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
,从而破坏了检查。