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

问题描述 投票:0回答:6

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

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

目前前两部分是从每个子类的

__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 的回答)。这使生活变得更容易,但仍然必须记住完成初始化,这次是在“构造函数”内。无论哪种方式,都无法强制执行完全初始化,这正是我正在寻找的。

python inheritance initialization
6个回答
14
投票

模板方法设计模式来救援:

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'

14
投票

您可以使用元类(并更新为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]

10
投票

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

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


0
投票

从子类的 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

0
投票

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

另一方面,如果人们从类派生并且必须修改初始化,他们应该意识到其中的含义 - 这不是您希望在普通 API 中拥有的东西。或者,您可以对最终初始化采取防御措施,并检查它是否已在依赖于它的方法中被调用(如果没有,则调用它或引发异常)。

© www.soinside.com 2019 - 2024. All rights reserved.