在 __init__中提出异常是否被认为是不好的形式?如果是这样,那么当某些类变量初始化为 None或类型不正确时抛出错误的可接受方法是什么?
__init__
None
我认为这是内置 ValueError异常的完美案例。
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__()中引发异常绝对没问题。没有其他好的方法来指示初始化程序中的错误条件,在标准库中有成百上千的例子表明初始化对象可能会引发异常。
__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 中做太多的工作是不好的风格。您应该考虑创建一个工厂或伪工厂-一个返回已设置对象的简单类方法。