Python 即使“\uuu init\uuu()”引发异常,也要使用对象吗?
我所处的情况是,类Python 即使“\uuu init\uuu()”引发异常,也要使用对象吗?,python,python-3.x,python-3.6,Python,Python 3.x,Python 3.6,我所处的情况是,类\uuuu init\uuuu方法中一些微不足道的重要部分可能会引发异常。在这种情况下,我希望显示一条错误消息,但继续使用实例 一个非常基本的例子: class something(object): def __init__(self): do_something_important() raise IrrelevantException() def do_something_useful(self): pass
\uuuu init\uuuu
方法中一些微不足道的重要部分可能会引发异常。在这种情况下,我希望显示一条错误消息,但继续使用实例
一个非常基本的例子:
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()
但是,最后一行不起作用,因为没有定义。奇怪的是,我可以发誓我以前做过这样的事情,效果很好。我甚至想了一些方法来阻止人们使用这样一个未完成的实例,因为我发现它即使在出现错误的情况下也会被创建。现在我想用它,但它不起作用。嗯
PS:
有些东西是我自己写的,所以我可以控制一切。你不能同时引发异常和返回值(如果不被攻击的话)。如果这是您控制的所有代码,那么我可以建议以下模式:
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
注意,如果您只是在寻找一条消息,那么不必费心创建一个异常对象,只需在self上设置一个错误代码/消息,稍后再进行检查。我假设您无法控制“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类不会运行其父构造函数,除非调用它 您可以通过调用object.\uuu new\uuu()
来创建对象来完成此操作。然后在调用\uuuu init\uuuu()
创建对象之后
这将执行所有可能的代码
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所指出的,编辑。此代码假定已定义了\uuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
现在,如果可以假定\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
但是,如果对象中有错误。
则无法创建实例,也无法对其应用中的操作
这是因为\uuuuuuuuuuuuuuuuuu()
返回实例,而\uuuuuuuuuuuu init()
操作实例。(当您调用something()
时,默认的\uuuu new\uuuu()
函数实际上调用\uuuu init\uuuuu()
,然后安静地返回实例。)
因此,该代码最健壮的版本是:
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()
因此,同时这两种方法都回答了这个问题,后一种方法在\uuuuu new\uuuuu()
出现错误的情况下(公认罕见)也会有所帮助,但这并不会阻止做一些有用的事()
的工作。评论:
PS:有些东西是我自己写的,所以我可以控制一切
那么,答案是显而易见的:只需删除raiseinterrelatexception()
当然,您真正的代码可能没有引发不相关异常
,而是调用一些可能引发异常的危险函数()。但那很好;您可以像在其他地方一样处理异常;您在\uuuu init\uuu
方法中这一事实没有什么区别:
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()
就这些。您的\uuuu init\uuuu
没有理由引发异常,因此如何处理该异常的问题从一开始就不会出现
如果您不能修改某个东西,但可以将其子类化,那么您不需要任何花哨的东西:
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()
现在调用了dou\u something\u important
,一个something
实例得到了返回,我可以保存并调用dou something\u有用的
等等。正是你想要的
当然,您可以使用一些巧妙的重命名技巧将某些东西
隐藏在更好的东西
后面:
_something = something
class something(_something):
# same code as above
…或者只是monkeypatch某个东西。_init__
使用包装函数而不是包装类:
_init = something.__init__
def __init__(self):
try:
_init(self)
except IrrelevantException:
pass
something.__init__ = __init__
但是,除非有很好的理由说明你不能明确说明你正在向它添加一个包装器,否则最好是明确的。在分配任务之前,必须成功地评估任务的右侧,因此,没有定义它也就不足为奇了。即使对象是创建的(在初始化之前),如果赋值失败,您也没有对它的引用,因此它将被垃圾收集。如果您确实在某处保留了引用,例如通过类或元类,那么您仍然可以对其调用方法。在构造函数中引发异常意味着无法构造该对象,因此您将无法使用它。如果在某种情况下,构造函数内部发生的事情可能会失败,但对象仍然会被构造,那么这些东西不应该是构造函数的一部分。@poke这有点误导\uuuu new\uuuu
是构造函数\uuuu init\uuuu
是初始值设定项。这种差异在这里是相关的,即使不是经常发生,因为你可以有一个返回有效对象的\uuuuuu new\uuuuuu
,然后是一个执行“无关内容”的\uuuuu init\uuuuuu
,你可以通过,例如,使用\uuuuuuuu init\uuuuu
方法或元类或任何将self
隐藏在某个地方来解决这个问题,但是在一个构造函数中,这是不起作用的。对于PS,这是一个很小的问题:只打印一个错误而不是引发一个异常,然后,如何处理其他异常的整个问题并不是首先出现的。即使我问了这个问题,我现在也会认为它是坏的风格。如果它能以这种方式工作,那将是一个难看的小故障,因为正如@jornsharpe所说的,在实际分配任务之前,必须成功地评估任务的右侧。没有rend可能会失败的代码