我处于这样的情况下,类__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()
但是,最后一行不起作用,因为未定义that_thing
。奇怪的是,我可以发誓以前做过这样的事情,而且效果很好。我什至讨论如何阻止人们使用未完成的实例的方法,因为我发现即使在发生错误的情况下它也会被创建。现在我想使用它,它不起作用。嗯...?!?
PS:something
是我自己写的,所以我可以控制一切。
答案 0 :(得分:2)
您不能同时引发异常和返回值(不会被黑客攻击)。如果这是您控制的所有代码,那么我可以建议以下模式:
class something(object):
Exception = None
def __init__(self):
...
if BadStuff:
self.Exception = IrrelevantException()
...
that_thing = something()
if that_thing.Exception:
print(that_thing.Exception)
# carry on
请注意,如果您只是在寻找一条消息,那么就不必费心创建Exception
对象,而只需在自己身上设置错误代码/消息,然后再进行检查即可。
答案 1 :(得分:2)
您可以通过调用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.
编辑,如@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()
因此,尽管这两个都回答了问题,但后一个问题也应在__new__()
有错误但不会阻止do_something_useful()
正常工作的情况下(在极少数情况下)提供帮助。 / p>
答案 2 :(得分:2)
来自评论:
PS:有些东西是我自己写的,所以我可以控制一切。
那么,答案很明显:只需删除raise IrrelevantException()
当然,您的实际代码可能没有raise IrrelevantException
,而是调用了可能引发的某些dangerous_function()
。但这很好;您可以像在其他任何地方一样处理异常。您在__init__
方法内部的事实没有任何区别:
class something(object):
def __init__(self):
do_something_important()
try:
do_something_dangerous()
except IrrelevantException as e:
print(f'do_something_dangerous raised {e!r}')
do_other_stuff_if_you_have_any()
仅此而已。您的__init__
没有理由提出异常,因此一开始就不会出现如何处理该异常的问题。
如果您不能修改something
,但是可以对其进行子类化,那么您就不需要花哨的东西了:
class IrrelevantException(Exception):
pass
def do_something_important():
pass
class something(object):
def __init__(self):
do_something_important()
raise IrrelevantException()
def do_something_useful(self):
pass
class betterthing(something):
def __init__(self):
try:
super().__init__() # use 2.x style if you're on 2.x of course
except IrrelevantException:
pass # or log it, or whatever
# You can even do extra stuff after the exception
that_thing = betterthing()
that_thing.do_something_useful()
现在调用了do_something_important
,并且返回了一个something
实例,我可以保存并调用do_something_useful
,依此类推。正是您要找的东西。
您当然可以通过一些巧妙的重命名技巧将something
隐藏在betterthing
后面:
_something = something
class something(_something):
# same code as above
…或仅使用包装函数而不是包装类的Monkeypatch something.__init__
:
_init = something.__init__
def __init__(self):
try:
_init(self)
except IrrelevantException:
pass
something.__init__ = __init__
但是,除非有充分的理由不能明确说明要添加包装程序,否则最好是明确说明。
答案 3 :(得分:0)
我假设您无法控制“ something”类,因此在这种情况下,您可以直接调用该方法,前提是该类中不需要任何元素。不过,您传递的是self = None,因此它将无法访问该类的变量。
class IrrelevantException(Exception):
x = "i don't matter"
class something(object):
def __init__(self):
raise IrrelevantException()
def do_something_useful(self):
print('hi')
#this will fail
try:
that_thing = something()
except IrrelevantException:
print("Something less important failed.")
#this will run
something.do_something_useful(None)
或者您可以使用继承:
class mega_something(something):
def __init__(self):
print("its alive!")
that_other_thing = mega_something()
that_other_thing.do_something_useful()
除非调用mega_something类,否则不会运行其父构造函数。