【发布时间】:2013-01-25 16:23:40
【问题描述】:
在使用 PyCharm IDE 时,如果使用不带异常类型的 except: 会触发 IDE 提醒该异常子句是 Too broad。
我应该忽略这个建议吗?还是 Pythonic 总是指定异常类型?
【问题讨论】:
-
如果你想了解更多关于这个的信息而不是答案,谷歌吞咽异常。您可以在它们旁边进行各种其他有趣的注意事项。代码异味是另一种。
在使用 PyCharm IDE 时,如果使用不带异常类型的 except: 会触发 IDE 提醒该异常子句是 Too broad。
我应该忽略这个建议吗?还是 Pythonic 总是指定异常类型?
【问题讨论】:
【讨论】:
这里是我使用的地方,除了没有类型
这是我的代码中未检查异常的主要用途
我总是添加这个,这样生产代码就不会溢出堆栈跟踪
我有两种方法:
我更喜欢这种方式,我发现更容易检测到哪些异常应该被适当地捕获:当较低级别的异常被更高级别记录时,我可以更好地“看到”问题 p>
一些同事更喜欢这种方式,因为它可以在他们“所属”的低级函数中保留低级异常。
【讨论】:
指定明确的异常类型几乎总是更好。如果您使用裸露的except: 子句,您最终可能会捕获到您希望捕获的异常之外的异常 - 这可能会隐藏错误,或者在程序没有按照您的预期运行时使调试变得更加困难。
例如,如果您要向数据库中插入一行,您可能希望捕获一个表明该行已存在的异常,以便进行更新。
try:
insert(connection, data)
except:
update(connection, data)
如果您指定一个空的except:,您还会捕获一个套接字错误,表明数据库服务器已经崩溃。最好只捕获您知道如何处理的异常 - 程序在异常点失败通常比继续但以奇怪的意外方式表现更好。
您可能想要使用裸except: 的一种情况是您需要始终运行的程序的顶层,例如网络服务器。但是,您需要非常小心地记录异常,否则将无法找出问题所在。基本上,一个程序中最多应该只有一个地方可以做到这一点。
所有这一切的一个必然结果是您的代码永远不应该使用raise Exception('some message'),因为它会强制客户端代码使用except:(或except Exception:,这几乎一样糟糕)。您应该定义一个特定于您要发出信号的问题的异常(可能继承自一些内置异常子类,如ValueError 或TypeError)。或者你应该提出一个特定的内置异常。这使您的代码的用户能够小心地捕获他们想要处理的异常。
【讨论】:
except: 还捕获(以及许多其他内容)NameError 和 AttributeError,所以如果您在 try 块中拼错了某些内容(例如,您的“插入”函数实际上称为 insert_one因为有人没有像他们应该的那样重视一致性),它总是默默地尝试update()。
main())?
except Exception: 也会捕获 NameError 和 AttributeError。是什么让裸except: 如此糟糕的是它捕捉到了没有被捕捉到的东西,例如。 SystemExit(当你调用exit或sys.exit时引发,现在你已经阻止了预期的退出)和KeyboardInterrupt(同样,如果用户点击Ctrl-C,你可能不想继续运行只是为了惹恼他们)。只有后者才是真正有意义的捕捉,它应该被明确捕捉。至少except Exception: 让这两个正常传播。
您不应忽视口译员给您的建议。
来自PEP-8 Python 风格指南:
在捕获异常时,只要提及特定的异常 可以代替使用裸的 except: 子句。
例如,使用:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
一个简单的 except: 子句将捕获 SystemExit 和 KeyboardInterrupt 异常,使其更难 使用 Control-C 中断程序,并且可以掩饰其他问题。 如果要捕获所有表明程序错误的异常,请使用 except Exception:(裸的 except 等价于 except BaseException:)。
一个好的经验法则是将裸“除外”子句的使用限制为两个 案例:
如果异常处理程序将打印或记录 追溯;至少用户会意识到发生了错误。 如果代码需要做一些清理工作,然后让异常 随着 raise 向上传播。尝试...终于可以成为更好的方法 处理这个案子。
这不是 Python 特有的。
例外的全部意义在于尽可能接近问题的原因来处理问题。
因此,您保留在特殊情况下可能触发问题的代码和解决方案“相邻”。
问题是您无法知道一段代码可能引发的所有异常。你所能知道的是,如果它是一个说找不到文件的异常,那么你可以捕获它并提示用户获取一个执行或取消该功能。
如果你把 try catch 放在那个周围,那么无论你的文件例程中有什么问题(只读、权限、UAC、不是真正的 pdf 等),每个人都会进入你的文件 not found catch,你的用户在尖叫“但它就在那里,这段代码是垃圾”
现在有几种情况你可能会抓住一切,但应该有意识地选择它们。
它们是捕获,撤消一些本地操作(例如创建或锁定资源,(例如打开磁盘上的文件进行写入),然后再次抛出异常,以供更高级别处理)
另一个你不在乎为什么会出错。以印刷为例。你可能有一个问题,说你的打印机有问题,请解决它,不要因为它而杀死应用程序。如果您的代码使用某种时间表执行一系列单独的任务,那么类似的徒劳无功,您不会希望整个事情都死掉,因为其中一个任务失败了。
注意如果您执行上述操作,我不能推荐某种异常日志记录,例如尝试捕获日志结束,足够高。
【讨论】:
总是指定异常类型,有很多类型你不想捕获,比如SyntaxError、KeyboardInterrupt、MemoryError等。
【讨论】:
except Exception: 避免上述我们不想捕获的类型吗?
except Exception 很好。
except Exception 捕获 SyntaxError 和 MemoryError 因为它是它们的基类。 KeyboardInterrupt、SystemExit(由sys.exit() 引发)未被捕获(它们是直接的 BaseException 子类)
您还将捕捉到例如使用 Control-C,所以除非你再次“抛出”它,否则不要这样做。但是,在这种情况下,您应该使用“finally”。
【讨论】: