一组共享共同父类的类的初始化过程可以分为三个部分:
目前前两部分是从每个子类的
__init__
方法中调用的,但最后的初始化后部分必须单独调用,例如
class BaseClass:
def __init__(self):
print 'base __init__'
self.common1()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
class Subclass1(BaseClass):
def __init__(self):
BaseClass.__init__(self)
self.specific()
def specific(self):
print 'specific'
if __name__ == '__main__':
s = Subclass1() # Don't forget to finalize the initialization
s.finalizeInitialization() # now the object is fully initialized
有没有办法不用打电话
finalizeInitialization()
?或者可以将 finalizeInitialization()
的呼叫转移到 Subclass1
的 __init__
(如 S.Lott 的回答)。这使生活变得更容易,但仍然必须记住完成初始化,这次是在“构造函数”内。无论哪种方式,都无法强制执行完全初始化,这正是我正在寻找的。
模板方法设计模式来救援:
class BaseClass:
def __init__(self, specifics=None):
print 'base __init__'
self.common1()
if specifics is not None:
specifics()
self.finalizeInitialization()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
class Subclass1(BaseClass):
def __init__(self):
BaseClass.__init__(self, self.specific)
def specific(self):
print 'specific'
您可以使用元类(并更新为Python3代码):
class PostInitCaller(type):
def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
obj.__post_init__()
return obj
class BaseClass(metaclass=PostInitCaller):
def __init__(self):
print('base __init__')
self.common1()
def common1(self):
print('common 1')
def finalizeInitialization(self):
print('finalizeInitialization [common2]')
def __post_init__(self): # this is called at the end of __init__
self.finalizeInitialization()
class Subclass1(BaseClass):
def __init__(self):
super().__init__()
self.specific()
def specific(self):
print('specific')
s = Subclass1()
base __init__
common 1
specific
finalizeInitialization [common2]
版本 1 - 委托一切。
class Subclass1(BaseClass):
def __init__(self):
super( Subclass1, self ).__init__()
self.specific()
super( Subclass1, self ).finalizeInitialization()
版本 2 - 仅委托一步
class BaseClass:
def __init__(self):
print 'base __init__'
self.common1()
self.specific()
self.finalizeInitialization()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
def specific( self ):
# two choices:
# if this is "abstract": raise an exception
# if this is "concrete": pass
与 S. Lott 的方法类似,只不过派生类没有办法(无法重写
__init__
)来重写(甚至调用)通用方法:
class BaseClass:
def __init__(self):
def common():
print "common initialization..."
def final():
print "common finalization..."
common()
self.specific()
final()
def final_init(self):
print "BaseClass.final_init"
class Subclass1(BaseClass):
def specific(self):
print "Subclass1.specific"
如果在创建不提供自己的实现的任何子类的实例时不能引发
specific
,您可能希望在 BaseClass
中提供 AttributeError
的默认实现。
从子类的 init 中调用 FinalInitilazation 有什么问题吗?
class BaseClass:
def __init__(self):
print 'base __init__'
self.common1()
def common1(self):
print 'common 1'
def finalizeInitialization(self):
print 'finalizeInitialization [common2]'
class Subclass1(BaseClass):
def __init__(self):
BaseClass.__init__(self)
self.specific()
BaseClass.finalizeInitialization(self)
def specific(self):
print 'specific'
if __name__ == '__main__':
s = Subclass1() #Don't forget to finalize the initialization
s.finalizeInitialization() # now the object is fully initialized
如果必须按特定顺序调用多个方法,通常意味着设计一开始就存在问题(泄漏了实现细节)。所以我会尝试从这一点开始工作。
另一方面,如果人们从类派生并且必须修改初始化,他们应该意识到其中的含义 - 这不是您希望在普通 API 中拥有的东西。或者,您可以对最终初始化采取防御措施,并检查它是否已在依赖于它的方法中被调用(如果没有,则调用它或引发异常)。