我需要一种从抽象方法调用函数的方法,即
class A(object):
@abc.abstractmethod
def method1(self):
raise Exception("Unimplemented method")
def method2(self):
print "method1 finished"
class B(A):
def method1(self):
print "executing method1 from class B"
我需要一种在method2
执行后自动调用A
类method1
的方法(应该在类A
方面完成 - 独立于继承的类)。
这样做有什么好办法吗?
答案 0 :(得分:3)
您可以使用元类,它在创建类时包装method1
:
from functools import wraps
class MetaA(type):
def __new__(meta, name, bases, attr):
method1 = attr['method1']
if not getattr(method, '__isabstractmethod__'):
@wraps(method1)
def wrapper(self, *args, **kw):
res = method1(self, *args, **kw)
self.method2()
return res
attr['method1'] = wrapper
return super(MetaA, meta).__new__(meta, name, bases, attr)
class A(object):
__metaclass__ = MetaA
@abc.abstractmethod
def method1(self):
raise Exception("Unimplemented method")
def method2(self):
print "method1 finished"
这适用于创建(子)类时基本上是特定方法的装饰器。
另一种方法,有点hackish,是截取方法访问,但会工作。您在__getattribute__
上实现了A
挂钩,它添加了一个包装器:
from functools import wraps
class A(object):
@abc.abstractmethod
def method1(self):
raise Exception("Unimplemented method")
def method2(self):
print "method1 finished"
def __getattribute__(self, name):
obj = super(A, self).__getattribute__(name)
if name == 'method1':
@wraps(obj)
def wrapper(*args, **kw):
res = obj()
self.method2()
return res
return wrapper
return obj
任何一种方法都会产生:
>>> B().method1()
executing method1 from class B
method1 finished
通过使用@functools.wraps()
decorator,包装器会保留包装方法中的几个重要属性,例如名称和文档字符串。
答案 1 :(得分:1)
这看起来像是Template method模式的工作,例如:
class A(object):
def method1(self):
# do something before
try:
self.method1_impl()
finally:
# do something after, for example:
self.method2()
@abc.abstractmethod
def method1_impl(self):
pass
def method2(self):
print "method1 finished"
class B(A):
def method1_impl(self):
print "executing method1 from class B"
虽然我不是这种风格的支持者(随着代码的增长和变得越来越复杂,它往往变得难以理解),但偶尔会使用它并且有权存在。
答案 2 :(得分:1)
当出现这种情况时,通常可以通过覆盖“更深层次”功能来解决。
不要让class B
覆盖method1
,而是覆盖method1_subfunction
,并从method1_subfunction
method1
>
class A(object):
def method1(self):
self.method1_subfunction()
self.method2()
@abc.abstractmethod
def method1_subfunction(self):
raise Exception("Unimplemented method")
def method2(self):
print "method1 finished"
class B(A):
def method1_subfunction(self):
print "executing method1 from class B"