__init__ 可以用作正常的初始化方法,而不是构造函数吗?

May __init__ be used as normal method for initialization, not as constructor?

有时使用__init__作为已经存在的对象的初始化方法看起来是合理的,即:

class A():
    def __init__(self, x):
        self.x = x

    def set_state_from_file(self, file):
        x = parse_file(file)
        self.__init__(x)

作为此实现的替代方案,我看到以下内容:

class A():
    def __init__(self, x):
        self.init(x)        

    def init(self, x):
        self.x = x

    def set_state_from_file(self, file):
        x = parse_file(file)
        self.init(x)

在我看来,代码过于复杂。这种情况有什么指导方针吗?

更新: 有一种情况绝对不是替代构造函数情况:unpickling。在 unpickling 期间,pickle 首先创建一个实例,然后才设置它的状态。

__init__ 不是构造函数。它是一个初始化方法,在实例已经为你构建之后被称为(实际的构造函数方法被称为__new__())。

如果您需要重新初始化,您可以随时从您的代码中再次调用它,这不是一种风格违规。事实上,它被用在 Python 标准库中;参见 multiprocessing.heap.Heap() implementation 例如:

def malloc(self, size):
    # return a block of right size (possibly rounded up)
    assert 0 <= size < sys.maxsize
    if os.getpid() != self._lastpid:
        self.__init__()                     # reinitialize after fork

threading.local implementation,它使用上下文管理器来延迟初始化。

__init__ 方法本身并没有什么特别之处。它仅由 type.__call__ 自动调用(在使用 instance = cls.__new__(cls, *args, **kwargs) 创建实例后,如果可用,则调用 cls.__init__(instance, *args, **kwargs))。

除了Martjin的回答:Python中的一个常见模式是使用classmethods作为工厂方法,即:

class A():
    def __init__(self, x):
        self.x = x

    @classmethod
    def from_file(cls, file):
        x = parse_file(file)
        return cls(x)


a1 = A(42)
a2 = A.from_file(open("/path/to/file"))

我发现 __init__ 和 'normal' 方法之间存在一些差异:

1., __init__ 不允许 return 任何东西:将引发 TypeError。

2., 如果 __init__ 引发错误, __del__ 将被调用: Martijn Pieters 的更新:这仅适用于构造函数调用,不适用于一般用法,请参阅下面的评论。

 class A(object):
     def __init__(self):
           print('__init__')
           raise ValueError('__init__ error')
           pass

    def method(self):
        raise ValueError('method error')

    def __del__(self):
        print("__del__")

def main():
    try:
        a = A()
        a.method()
    except ValueError as e:
        print(e)
    print('exit main')

if __name__ == '__main__':
    main()
    print('end of file')

将输出:

__init__
__init__ error
__del__
exit main
end of file