在finally
条款中,是否可以判断是否存在异常?类似的东西:
try:
funky code
finally:
if ???:
print('the funky code raised')
我希望这样做更干嘛:
try:
funky code
except HandleThis:
# handle it
raised = True
except DontHandleThis:
raised = True
raise
else:
raised = False
finally:
logger.info('funky code raised %s', raised)
我不喜欢它需要捕获一个你不打算处理的异常,只是为了设置一个标志。
因为有些comments要求的人数较少" M"在MCVE中,这里有一些关于用例的更多背景知识。实际问题是关于日志记录级别的升级。
logger.exception
在此处没有帮助。因此,代码在日志捕获上下文(设置自定义处理程序以拦截日志记录)下运行,并且一些调试信息会被追溯重新记录:
try:
with LogCapture() as log:
funky_code() # <-- third party badness
finally:
mylog = mylogger.WARNING if <there was exception> else mylogger.DEBUG
for record in log.captured:
mylog(record.msg, record.args)
答案 0 :(得分:40)
您可以使用自定义上下文管理器,例如:
class DidWeRaise:
__slots__ = ('exception_happened', ) # instances will take less memory
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# If no exception happened the `exc_type` is None
self.exception_happened = exc_type is not None
然后在try
:
try:
with DidWeRaise() as error_state:
# funky code
finally:
if error_state.exception_happened:
print('the funky code raised')
它仍然是一个额外的变量,但如果你想在多个地方使用它,它可能更容易重复使用。而且你不需要自己切换它。
如果您不想要上下文管理器,我会反转触发器的逻辑并仅在没有异常发生时将其切换为 。这样,您就不需要except
个案例来解决您不想处理的异常问题。最合适的地方是在else
没有引发异常的情况下输入的try
子句:
exception_happened = True
try:
# funky code
except HandleThis:
# handle this kind of exception
else:
exception_happened = False
finally:
if exception_happened:
print('the funky code raised')
正如已经指出的那样,而不是一个&#34;切换&#34;变量你可以用所需的日志功能替换它(在这种情况下):
mylog = mylogger.WARNING
try:
with LogCapture() as log:
funky_code()
except HandleThis:
# handle this kind of exception
else:
# In case absolutely no exception was thrown in the try we can log on debug level
mylog = mylogger.DEBUG
finally:
for record in log.captured:
mylog(record.msg, record.args)
当然,如果你把它放在你的try
的末尾也会有用(正如这里建议的其他答案),但我更喜欢else
条款,因为它有更多含义(&#34;该代码只有在try
块&#34;)中没有异常时才会执行,并且从长远来看可能更容易维护。虽然它比上下文管理器更需要维护,因为变量在不同的地方设置和切换。
sys.exc_info
(仅适用于未处理的例外)我想提到的最后一种方法可能对你没有用,但对于那些只想知道是否存在未处理的异常(异常< >不在任何except
块中捕获或已在except
块内引发。在这种情况下,您可以使用sys.exc_info
:
import sys
try:
# funky code
except HandleThis:
pass
finally:
if sys.exc_info()[0] is not None:
# only entered if there's an *unhandled* exception, e.g. NOT a HandleThis exception
print('funky code raised')
答案 1 :(得分:31)
mylog = WARNING
try:
funky code
mylog = DEBUG
except HandleThis:
# handle it
finally:
mylog(...)
鉴于在选择日志级别的问题中添加了额外的背景信息,这似乎很容易适应预期的用例:
{{1}}
答案 2 :(得分:3)
好的,听起来你实际上只想修改现有的上下文管理器,或者使用类似的方法:logbook
实际上有一个名为FingersCrossedHandler
的东西可以完全按照你想要的那样做。但你可以自己做,比如:
@contextmanager
def LogCapture():
# your existing buffer code here
level = logging.WARN
try:
yield
except UselessException:
level = logging.DEBUG
raise # Or don't, if you just want it to go away
finally:
# emit logs here
原始回复
你正在考虑这个问题。
你做打算处理异常 - 你通过设置一个标志来处理它。也许你不关心其他任何事情(这似乎是一个坏主意),但如果你在提出 异常时关心做某事,那么你想要明确它。 / p>
您正在设置变量,但希望异常继续,这意味着您真正想要的是从引发的异常中提出您自己的特定异常:
class MyPkgException(Exception): pass
class MyError(PyPkgException): pass # If there's another exception type, you can also inherit from that
def do_the_badness():
try:
raise FileNotFoundError('Or some other code that raises an error')
except FileNotFoundError as e:
raise MyError('File was not found, doh!') from e
finally:
do_some_cleanup()
try:
do_the_badness()
except MyError as e:
print('The error? Yeah, it happened')
这解决了:
MyPkgException
以捕获所有异常,以便它可以记录某些内容并退出状态良好而不是难看的堆栈跟踪答案 3 :(得分:2)
您可以轻松地将捕获的异常分配给变量,并在finally块中使用它,例如:
>>> x = 1
>>> error = None
>>> try:
... x.foo()
... except Exception as e:
... error = e
... finally:
... if error is not None:
... print(error)
...
'int' object has no attribute 'foo'
答案 4 :(得分:-1)
如果是我,我会对您的代码进行一些重新排序。
raised = False
try:
# funky code
except HandleThis:
# handle it
raised = True
except Exception as ex:
# Don't Handle This
raise ex
finally:
if raised:
logger.info('funky code was raised')
我已将引发的布尔赋值放在try语句之外以确保范围,并使最终的except语句成为您不想处理的异常的一般异常处理程序。
此样式确定您的代码是否失败。另一种方法可能是我确定代码何时成功。
success = False
try:
# funky code
success = True
except HandleThis:
# handle it
pass
except Exception as ex:
# Don't Handle This
raise ex
finally:
if success:
logger.info('funky code was successful')
else:
logger.info('funky code was raised')
答案 5 :(得分:-1)
如果发生异常->将此逻辑放在异常块中。
如果未发生异常->将此逻辑放在代码中可能发生异常的位置之后的try块中。
Finally blocks should be reserved for "cleanup actions," according to the Python language reference.当最终指定时,解释器将在 except 情况下进行如下操作:保存异常,然后 first首先执行finally块,最后引发异常。