__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
有时使用__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