如何在继承的Python类中执行常见的后初始化任务?

时间:2009-04-27 20:38:04

标签: python inheritance initialization

共享一个共同父类的一组类的初始化过程可以分为三个部分:

  • 常规初始化
  • 特定于子类的初始化
  • 常见的初始化后

目前前两个部分是从每个子类的__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's answer中)。这使得生活更轻松,但仍然需要记住完成初始化,这次是在“构造函数”中。无论哪种方式都无法实施完全初始化,这正是我正在寻找的。

5 个答案:

答案 0 :(得分:12)

拯救的模板方法设计模式:

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'

答案 1 :(得分:8)

版本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

答案 2 :(得分:1)

与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的默认实现实施

答案 3 :(得分:0)

从Subclass的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

答案 4 :(得分:0)

如果必须按特定顺序调用多个方法,通常意味着设计开始时会出现问题(它正在泄漏实现细节)。所以我会尝试从那时开始工作。

另一方面,如果人们从类中派生并且必须修改初始化,那么他们应该意识到这些含义 - 这不是你想要在普通API中拥有的东西。或者,您可能会对最终初始化进行防御,并检查它是否已在依赖于它的方法中调用(如果没有,则调用它或引发异常)。