在__init__
内提出异常会被视为不良形式吗?如果是这样,那么当某些类变量初始化为None
或类型不正确时,抛出错误的可接受方法是什么?
答案 0 :(得分:133)
在__init__()
内提出异常绝对没问题。没有其他好方法可以在构造函数中指出错误条件,并且标准库中有数百个示例,其中构建对象可能引发异常。
当然,要提出的错误类由您决定。如果构造函数传递了无效参数,则ValueError
最好。
答案 1 :(得分:22)
确实,在构造函数中指示错误的唯一正确方法是引发异常。这就是为什么在C ++和其他面向对象语言中考虑到异常安全性的原因,如果在对象的构造函数中抛出异常(意味着对象的初始化不完整),则不会调用析构函数。在脚本语言中通常不是这种情况,例如Python。例如,如果socket.connect()失败,则以下代码抛出AttributeError:
class NetworkInterface:
def __init__(self, address)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(address)
self.stream = self.socket.makefile()
def __del__(self)
self.stream.close()
self.socket.close()
原因是在初始化流属性之前,在连接尝试失败后调用不完整对象的析构函数。你不应该避免从构造函数中抛出异常,我只是说在Python中编写完全异常安全的代码是很困难的。一些Python开发人员完全避免使用析构函数,但这是另一个争论的问题。
答案 2 :(得分:11)
我认为没有任何理由认为它应该是不好的形式。
相反,与返回错误代码相反,其中一个例外的事情就是知道,错误代码通常不能由构造函数返回。所以至少在像C ++这样的语言中,提出异常是发出错误信号的唯一方法。
答案 3 :(得分:5)
标准库说:
>>> f = file("notexisting.txt")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'
此外,我真的没有理由认为它应该被视为不良形式。
答案 4 :(得分:3)
我认为这是内置ValueError
例外的完美案例。
答案 5 :(得分:2)
我同意上述所有内容。
除了引发异常之外,没有其他方法可以表明对象初始化时出现问题。
在大多数程序类中,类的状态完全依赖于该类的输入,我们可能会期望引发某种类型的ValueError或TypeError。
如果(例如)网络设备不可用或无法写入画布对象,则带有副作用的类(例如,具有网络或图形的类)可能会在init中引发错误。这对我来说听起来很明智,因为通常你想尽快了解失败情况。
答案 6 :(得分:2)
在某些情况下,从init中引发错误是不可避免的,但在init中做太多工作是一种糟糕的风格。您应该考虑创建工厂或伪工厂 - 一种返回设置对象的简单类方法。