child 类 在 python 中的修饰函数
Decorating functions of child classes in python
我认为这是一个非常简单的问题,但未能找到令人满意的答案。简而言之,我想在 parent 的 child class 上执行合同,而不向每个 child class 添加逻辑。下面的代码示例:
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
所以问题是如何auto-decorateclasses继承A1
实现的do_thing
功能?假设还有 A2
class 以及略有不同的检查。
我的初步调查表明元classes 是可以采用的方法,但很难找到关于它们如何工作的很好的解释。理想情况下寻找在 python 2.x 中起作用的东西,但如果只有 3.x 解决方案,我很乐意更改我的代码库。
首先:您错误地使用了abc
模块(see the docs)。你的 class A
应该有 abc.ABCMeta
作为元 class。因此,如果您已经在使用元 class,您可以扩展它以发挥您的优势。
一个元 class 继承自 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 带有一个什么也不做的默认检查装饰器:
# 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
必须是 class 方法。
对于在 python3
和 python2
中工作的元 classes,请参阅 six。
您的检查器 class 仅实现特定检查器但仍然是抽象的:
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)
会导致递归错误。
以及您的具体 class 示例实现 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
抽象化。
所以这已经是很多文本了,但是如果您根本不想使用任何元 classes,那么有一个更简单的方法:
编写一个class,使用两个"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
元 class。
现在创建一个实现 check_do_thing
的检查器 class
class Checker(Abstract):
def check_do_thing(self, result):
if result != 1:
raise ValueError("check failed")
这就变得简单多了,因为我们这里不需要装饰器。
最后是实现 do_thing_func
的具体 class
class Concrete(Checker):
def do_thing_func(self, input):
return input # sample implementation
注意 Concrete
现在必须实现 do_thing_func
但是当你使用 class 时你必须调用 do_thing
.
这里的缺点是您仍然可以覆盖 do_thing
从而破坏检查。
我认为这是一个非常简单的问题,但未能找到令人满意的答案。简而言之,我想在 parent 的 child class 上执行合同,而不向每个 child class 添加逻辑。下面的代码示例:
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
所以问题是如何auto-decorateclasses继承A1
实现的do_thing
功能?假设还有 A2
class 以及略有不同的检查。
我的初步调查表明元classes 是可以采用的方法,但很难找到关于它们如何工作的很好的解释。理想情况下寻找在 python 2.x 中起作用的东西,但如果只有 3.x 解决方案,我很乐意更改我的代码库。
首先:您错误地使用了abc
模块(see the docs)。你的 class A
应该有 abc.ABCMeta
作为元 class。因此,如果您已经在使用元 class,您可以扩展它以发挥您的优势。
一个元 class 继承自 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 带有一个什么也不做的默认检查装饰器:
# 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
必须是 class 方法。
对于在 python3
和 python2
中工作的元 classes,请参阅 six。
您的检查器 class 仅实现特定检查器但仍然是抽象的:
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)
会导致递归错误。
以及您的具体 class 示例实现 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
抽象化。
所以这已经是很多文本了,但是如果您根本不想使用任何元 classes,那么有一个更简单的方法:
编写一个class,使用两个"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
元 class。
现在创建一个实现 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
但是当你使用 class 时你必须调用 do_thing
.
这里的缺点是您仍然可以覆盖 do_thing
从而破坏检查。