即使 `__init__()` 引发异常也使用对象?

Bac*_*sau 4 python python-3.x python-3.6

我所处的情况是类__init__方法的一些微不足道的重要部分可能会引发异常。在这种情况下,我想显示一条错误消息,但继续使用该实例。

一个非常基本的例子:

class something(object):
    def __init__(self):
        do_something_important()
        raise IrrelevantException()

    def do_something_useful(self):
        pass

try:
    that_thing = something()
except IrrelevantException:
    print("Something less important failed.")

that_thing.do_something_useful()
Run Code Online (Sandbox Code Playgroud)

但是,最后一行不起作用,因为that_thing未定义。奇怪的是,我可以发誓我以前做过类似的事情而且效果很好。我什至想过如何阻止人们使用这样一个未完成的实例,因为我发现即使出现错误它也会被创建。现在我想用它,但它不起作用。嗯...?!?

PS:something是我自己写的,所以我可以控制一切。

The*_*att 5

您可以通过调用object.__new__()创建对象来完成此操作。然后调用__init__()创建对象。

这将执行所有可能的代码。

class IrrelevantException(Exception):
    """This is not important, keep executing."""
    pass

class something(object):
    def __init__(self):
        print("Doing important stuff.")
        raise IrrelevantException()

    def do_something_useful(self):
       print("Now this is useful.")

that_thing = object.__new__(something) # Create the object, does not call __init__
try:
    that_thing.__init__() # Now run __init__
except IrrelevantException:
    print("Something less important failed.")

that_thing.do_something_useful() # And everything that __init__ could do is done.
Run Code Online (Sandbox Code Playgroud)

编辑,正如@abarnert 指出的。此代码确实假定已__init__()定义,但__new__()实际上并未定义。

现在如果可以假设__new__()不会出错,就可以object.__new__()在代码中替换。

但是,如果 中存在错误object.__new__(),则无法创建实例并__new__()对其应用 中的操作。

这是因为__new__()返回实例,而不是__init__()操纵实例。(当您调用 时something(),默认__new__()函数实际上会调用__init__(),然后悄悄返回实例。)

所以这段代码最健壮的版本是:

class IrrelevantException(Exception):
    """This is not important, keep executing."""
    pass

class something(object):
    def __init__(self):
        print("Doing important stuff.")
        raise IrrelevantException()

    def do_something_useful(self):
       print("Now this is useful.")

try:
    that_thing = something.__new__(something) # Create the object, does not call __init__
except IrrelevantException:
    # Well, just create the object without calling cls.__new__()
    that_thing = object.__new__(something)
try:
    that_thing.__init__() # Now run __init__
except IrrelevantException:
    print("Something less important failed.")

that_thing.do_something_useful()
Run Code Online (Sandbox Code Playgroud)

因此,同时这两个都回答了问题,后一个也应该在__new__()出现错误的(诚然罕见)情况下有所帮助,但这并不会停止do_something_useful()工作。