从构造函数中以正确的顺序调用加载函数

2024-04-28 07:37:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个班,如下所示:

class Super(object):
    def __init__(self, arg):
        self.arg = arg

    def load(self):
        # Load data from disk if available
        try:
            self.data = load_routine()
        except IOError as e:
            if e[0] == errno.ENOENT:
                pass
            else:
                raise


class Sub(Super):
    def __init__(self, arg2, *args, **kwargs):
        super(Sub, self).__init__(*args, **kwargs)
        self.arg2 = arg2

    def load(self):
        # Load files specific to superclass
        super(Sub, self).load()
        # Load data from disk if available
        try:
            self.data2 = another_different_load_routine(self.arg2)
        except IOError as e:
            if e[0] == errno.ENOENT:
                pass
            else:
                raise

{I希望这两个类都能很好的使用。在

但是,实际上我希望load方法在__init__()结束时自动调用,但我不确定如何实现这一点。{{If}将从cd2>的子类的实例中同时调用一次。在

如果我只将对self.load()的调用放在超类的init方法的末尾,那么它将只被调用一次,但对象还没有初始化为包含加载所需的属性。在

当实例化Sub时,我希望它初始化__init__中父类和子类的所有属性,并为父类和子类调用load()。是否按顺序

Super -> __init__()Super -> load()Sub -> __init__()Sub -> load()

或者

Super -> __init__()Sub -> __init__()Super -> load()Sub -> load()

不重要。我怎样才能做到这一点?在


Tags: fromselfdataifinitdefargload
2条回答

答案是您未能列举的组合:

class Super(object):
    def __init__(self):
        print 'init super'
        if self.__class__ == Super:
            self.load()
    def load(self):
        print 'load super'

class Sub(Super):
    def __init__(self):
        # always do super first in init
        super(Sub, self).__init__()
        print 'init sub'
        self.load()
    def load(self):
        # load is essentially an extension of init
        # so you still need to call super first
        super(Sub, self).load()
        print 'load sub'

sub = Sub()

如果你真的想实例化super(它不是一个抽象类),你需要在它的init中进行if测试。否则,您无法使用当前的类结构和初始化方案获得所需的有序语义。在

Sub()将调用Sub.__init__,它将调用Super.__init__(在执行任何操作之前)。在

之后,__init__上的Sub将完成它的工作。在

最后,Sub.__init__将调用Sub.load,它将调用Super.load(在做任何事情之前),然后自己做。在

“正常”的方法是

^{pr2}$

根本没有调用__init__方法的load。如果您真的想调用load中的级别,这可能是我推荐的,因为它实际上是__init__的第二组

编辑:阅读前两个版本中关于失败的评论(并查看编辑以查看旧版本)。下面是另一个版本,使用元类:

class Loader(type):
    def __new__(cls, name, bases, attrs):
        if attrs.get('__init__'):
            attrs['_init'] = attrs['__init__']
            del attrs['__init__']
        if attrs.get('_init_'):
            attrs['__init__'] = lambda self: self._init_()
            attrs['_init'] = lambda self: None
        return super(Loader, cls).__new__(cls, name, bases, attrs)

class Super(object):
    __metaclass__ = Loader
    def _init_(self):
        print 'init super'
        self._init()
        self.load()

    def load(self):
        print 'load super'

class Sub(Super):
    def __init__(self):
        print 'init sub'

    def load(self):
        super(Sub, self).load()
        print 'load sub'


sub = Sub()
sup = Super()

这有一个不同的限制:所有子类都可以正常工作,除了不能通过使用super().__init__()调用Sub.__init__。我认为有可能删除这个限制,但是我不知道在没有另一层间接寻址的情况下如何。在

如果您总是希望__init__()完全初始化对象,然后调用load(),那么我将把这两个函数提取到单独的方法中:

class Super(object):
    def __init__(self, *args, **kw):
        self._initialise(*args, **kw)
        self.load()

    def _initialise(self, arg):
        self.arg = arg

    def load(self):
        ... as before ...


class Sub(Super):
    def _initialise(self, arg2, *args, **kwargs):
        super(Sub, self)._initialise(*args, **kwargs)
        self.arg2 = arg2

    def load(self):
        super(Sub, self).load()
        ... as before ...

现在你有一个你没有重写的__init__(),你不再把初始化和加载这两个单独的操作混合在一起。在

相关问题 更多 >