Skip to main content
 首页 » 编程设计

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

2025年05月04日9Leo_wl

我有如下两个类:

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 

我希望代码足够清晰,除非我遗漏了什么,否则这应该适用于两个类,例如:obj = Super(); obj.load().

但是,我实际上希望在 __init__() 结束时自动调用 load 方法,但我不确定如何实现这一点。如果我在 __init__() 的末尾添加 self.load() 两个类的 load() 子类的方法将被调用两次,如果尝试创建 Sub 的实例,一次来自父类(super class),一次来自子类。

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

在实例化 Sub 时,我真正想要的是为父类(super class)和子类初始化 __init__ 中的所有属性,并调用 load() 用于父类(super class)和子类。是否有序

Super -> __init__(), Super -> load(), Sub -> __init__(), Sub -> 加载()

或

Super -> __init__(), Sub -> __init__(), Super -> load(), Sub -> 加载()

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

请您参考如下方法:

答案是你没能列举出来的组合:

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__(在执行任何操作之前)。

之后,Sub 上的__init__ 将执行此操作。

最后,Sub.__init__ 将调用 Sub.load,这将调用 Super.load(在执行任何操作之前),然后执行它自己的作品。

执行此操作的“正常”方法是

sub = Sub() 
sub.load() 
sup = Super() 
sup.load() 

根本没有 __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__。我认为可以取消此限制,但如果没有另一层间接层,我目前还不知道如何做到这一点。