Python: 在__ init__ 中引发异常是不是不好的形式?

__init__中提出异常是否被认为是不好的形式?如果是这样,那么当某些类变量初始化为 None或类型不正确时抛出错误的可接受方法是什么?

70578 次浏览

我认为这是内置 ValueError异常的完美案例。

标准图书馆说:

>>> 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'

而且我也看不出有什么理由认为这是一种不好的形式。

__init__()中引发异常绝对没问题。没有其他好的方法来指示初始化程序中的错误条件,在标准库中有成百上千的例子表明初始化对象可能会引发异常。

当然,要引发的错误类取决于您。如果向初始值设定项传递了无效参数,则 ValueError是最佳选择。

我看不出有什么不好的理由。

相反,与返回错误代码相反,异常的优点之一是,错误代码通常由构造函数返回。因此,至少在 C + + 这样的语言中,引发异常是发出错误信号的唯一方法。

我同意以上所有观点。

除了引发异常之外,实际上没有其他方法可以表明对象的初始化出了问题。

在大多数程序类中,一个类的状态完全依赖于该类的输入,我们可能预期某种 ValueError 或 TypeError 将被引发。

具有副作用的类(例如,具有网络或图形功能的类)可能会在 init 中引发错误,如果(例如)网络设备不可用或无法写入画布对象。对我来说,这听起来很合理,因为通常您想尽快了解失败条件。

确实,指示构造函数中错误的唯一正确方法是引发异常。这就是为什么在 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 开发人员完全避免使用析构函数,但这是另一个争论的问题。

在某些情况下,从 init 引发错误是不可避免的,但是在 init 中做太多的工作是不好的风格。您应该考虑创建一个工厂或伪工厂-一个返回已设置对象的简单类方法。